3

我正在尝试这个:

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

并期望输出为:

0.0009

但输出是:

0.00089999999999999998

g++ 版本:5.4.0,升压版本:1.66

我能做些什么来让它打印出它得到的东西。

4

3 回答 3

3

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

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
于 2018-02-03T14:35:25.637 回答
3

boost::lexical_cast将浮点数转换为其字符串表示时,不允许您指定精度。从文档

对于更多涉及的转换,例如精度或格式需要比默认行为提供的更严格的控制lexical_cast,建议使用传统std::stringstream方法。

所以你可以使用stringstream

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

或者另一种选择是使用boost::format库。

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

两者都会打印0.0009

于 2018-02-03T09:37:48.597 回答
2

0.0009是一个双精度浮点文字,假设 IEEE754,值

0.00089999999999999997536692664112933925935067236423492431640625

这就是boost::lexical_cast<std::string>函数参数。格式化程序中的默认精度设置cout是四舍五入到第 17 位有效数字:

0.00089999999999999998

真的,如果你想要精确的小数精度,那么使用小数类型(Boost 有一个),或者使用整数并自己拼接小数分隔符。但在您的情况下,鉴于您只是在没有复杂计算的情况下输出数字,四舍五入到第 15 位有效数字将产生预期的效果:

std::setprecision(15)

进入输出流。

于 2018-02-03T10:23:06.490 回答