Merge pull request #1653 from strk/master-float-scientific
Implement scientific notation for double-to-string
This commit is contained in:
commit
e7891a99ce
2 changed files with 73 additions and 5 deletions
|
@ -70,12 +70,80 @@ template <typename T>
|
||||||
struct double_policy : boost::spirit::karma::real_policies<T>
|
struct double_policy : boost::spirit::karma::real_policies<T>
|
||||||
{
|
{
|
||||||
typedef boost::spirit::karma::real_policies<T> base_type;
|
typedef boost::spirit::karma::real_policies<T> base_type;
|
||||||
static int floatfield(T n) { return base_type::fmtflags::fixed; }
|
|
||||||
static unsigned precision(T n) { return static_cast<unsigned>(15 - boost::math::trunc(log10(n))); }
|
static int floatfield(T n) {
|
||||||
|
using namespace boost::spirit; // for traits
|
||||||
|
|
||||||
|
if (traits::test_zero(n))
|
||||||
|
return base_type::fmtflags::fixed;
|
||||||
|
|
||||||
|
T abs_n = traits::get_absolute_value(n);
|
||||||
|
return (abs_n >= 1e16 || abs_n < 1e-4)
|
||||||
|
? base_type::fmtflags::scientific : base_type::fmtflags::fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned precision(T n) {
|
||||||
|
if ( n == 0.0 ) return 0;
|
||||||
|
using namespace boost::spirit; // for traits
|
||||||
|
return static_cast<unsigned>(15 - boost::math::trunc(log10(traits::get_absolute_value(n))));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename OutputIterator>
|
template <typename OutputIterator>
|
||||||
static bool dot(OutputIterator& sink, T n, unsigned precision) {
|
static bool dot(OutputIterator& sink, T n, unsigned precision) {
|
||||||
return n ? *sink = '.', true : false;
|
if (n == 0.0) return true; // avoid trailing zeroes
|
||||||
|
return base_type::dot(sink, n, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
static bool fraction_part (OutputIterator& sink, T n
|
||||||
|
, unsigned precision_, unsigned precision)
|
||||||
|
{
|
||||||
|
// NOTE: copied from karma only to avoid trailing zeroes
|
||||||
|
// (maybe a bug ?)
|
||||||
|
|
||||||
|
// allow for ADL to find the correct overload for floor and log10
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
using namespace boost::spirit; // for traits
|
||||||
|
using namespace boost::spirit::karma; // for char_inserter
|
||||||
|
using namespace boost; // for remove_const
|
||||||
|
|
||||||
|
if ( traits::test_zero(n) ) return true; // this part added to karma
|
||||||
|
|
||||||
|
// The following is equivalent to:
|
||||||
|
// generate(sink, right_align(precision, '0')[ulong], n);
|
||||||
|
// but it's spelled out to avoid inter-modular dependencies.
|
||||||
|
|
||||||
|
typename remove_const<T>::type digits =
|
||||||
|
(traits::test_zero(n) ? 0 : floor(log10(n))) + 1;
|
||||||
|
bool r = true;
|
||||||
|
for (/**/; r && digits < precision_; digits = digits + 1)
|
||||||
|
r = char_inserter<>::call(sink, '0');
|
||||||
|
if (precision && r)
|
||||||
|
r = int_inserter<10>::call(sink, n);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharEncoding, typename Tag, typename OutputIterator>
|
||||||
|
static bool exponent (OutputIterator& sink, long n)
|
||||||
|
{
|
||||||
|
// NOTE: copied from karma to force sign in exponent
|
||||||
|
const bool force_sign = true;
|
||||||
|
|
||||||
|
using namespace boost::spirit; // for traits
|
||||||
|
using namespace boost::spirit::karma; // for char_inserter, sign_inserter
|
||||||
|
|
||||||
|
long abs_n = traits::get_absolute_value(n);
|
||||||
|
bool r = char_inserter<CharEncoding, Tag>::call(sink, 'e') &&
|
||||||
|
sign_inserter::call(sink, traits::test_zero(n)
|
||||||
|
, traits::test_negative(n), force_sign);
|
||||||
|
|
||||||
|
// the C99 Standard requires at least two digits in the exponent
|
||||||
|
if (r && abs_n < 10)
|
||||||
|
r = char_inserter<CharEncoding, Tag>::call(sink, '0');
|
||||||
|
return r && int_inserter<10>::call(sink, abs_n);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,11 +49,11 @@ int main( int, char*[] )
|
||||||
out.clear();
|
out.clear();
|
||||||
|
|
||||||
to_string(out, double(1e-05));
|
to_string(out, double(1e-05));
|
||||||
BOOST_TEST_EQ( out, "0.00001" );
|
BOOST_TEST_EQ( out, "1e-05" );
|
||||||
out.clear();
|
out.clear();
|
||||||
|
|
||||||
to_string(out, double(-1e-05));
|
to_string(out, double(-1e-05));
|
||||||
BOOST_TEST_EQ( out, "-0.00001" );
|
BOOST_TEST_EQ( out, "-1e-05" );
|
||||||
out.clear();
|
out.clear();
|
||||||
|
|
||||||
to_string(out, double(0.0001));
|
to_string(out, double(0.0001));
|
||||||
|
|
Loading…
Reference in a new issue