boost lexical cast double to string giving invalid results

时间:2018-02-03 08:17:12

标签: c++ boost double precision boost-lexicalcast

I am trying this:

std::cout << boost::lexical_cast<std::string>(0.0009) << std::endl;

and expecting the output to be:

0.0009

But the output is:

0.00089999999999999998

g++ version: 5.4.0, Boost version: 1.66

What can I do to make it print what it's been given.

3 个答案:

答案 0 :(得分:3)

boost::lexical_cast doesn't allow you to specify the precision when converting a floating point number into its string representation. From the documentation

For more involved conversions, such as where precision or formatting need tighter control than is offered by the default behavior of lexical_cast, the conventional std::stringstream approach is recommended.

So you could use stringstream

double d = 0.0009;
std::ostringstream ss;
ss << std::setprecision(4) << d;
std::cout << ss.str() << '\n';

Or another option is to use the boost::format library.

std::string s = (boost::format("%1$.4f") % d).str();
std::cout << s << '\n';

Both will print 0.0009.

答案 1 :(得分:2)

0.0009 is a double precision floating literal with, assuming IEEE754, the value

0.00089999999999999997536692664112933925935067236423492431640625

That's what boost::lexical_cast<std::string> sees as the function parameter. And the default precision setting in the cout formatter is rounding to the 17th significant figure:

0.00089999999999999998

Really, if you want exact decimal precision, then use a decimal type (Boost has one), or work in integers and splice in the decimal separator yourself. But in your case, given that you're simply outputting the number with no complex calculations, rounding to the 15th significant figure will have the desired effect: inject

std::setprecision(15)

into the output stream.

答案 2 :(得分:2)

可以实际上覆盖默认精度:

<强> Live On Coliru

#include <boost/lexical_cast.hpp>

#ifdef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
#    error unsupported
#endif

template <> struct boost::detail::lcast_precision<double> : std::integral_constant<unsigned, 5> { };

#include <string>
#include <iostream>

int main() {
    std::cout << boost::lexical_cast<std::string>(0.0009) << std::endl;
}

打印

0.0009

然而,这两者都不受支持(detail::)且不灵活(现在所有双打都会以这种方式出现)。

真正的问题

问题是从十进制表示转换为二进制表示的精度损失。而是使用十进制浮点表示:

<强> Live On Coliru

#include <boost/lexical_cast.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <string>
#include <iostream>

using Double = boost::multiprecision::cpp_dec_float_50;

int main() {
    Double x("0.009"),
           y = x*2,
           z = x/77;

    for (Double v : { x, y, z }) {
        std::cout << boost::lexical_cast<std::string>(v) << "\n";
        std::cout << v << "\n";
    }
}

打印

0.009
0.009
0.018
0.018
0.000116883
0.000116883