将 lexical_cast double 提升为字符串,给出无效结果
boost lexical cast double to string giving invalid results
我正在尝试这个:
std::cout << boost::lexical_cast<std::string>(0.0009) << std::endl;
并期望输出为:
0.0009
但输出是:
0.00089999999999999998
g++版本:5.4.0,Boost版本:1.66
我该怎么做才能让它打印出给定的内容。
boost::lexical_cast
不允许您在将浮点数转换为其字符串表示形式时指定精度。来自 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.
所以你可以使用 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
是双精度浮点文字,假设 IEEE754,值
0.00089999999999999997536692664112933925935067236423492431640625
这就是 boost::lexical_cast<std::string>
所看到的函数参数。 cout
格式化程序中的默认精度设置四舍五入到第 17 位有效数字:
0.00089999999999999998
真的,如果你想要精确的 decimal 精度,那么使用 decimal 类型(Boost 有一个),或者使用整数并自己拼接小数分隔符。但在你的情况下,假设你只是输出没有复杂计算的数字,四舍五入到第 15 位有效数字将产生预期的效果: inject
std::setprecision(15)
进入输出流。
您 可以 实际上覆盖默认精度:
#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::
) 又不灵活(现在所有双打都会以这种方式出现)。
真正的问题
问题是从十进制表示形式转换为二进制表示形式时精度下降。相反,使用十进制浮点数表示:
#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
我正在尝试这个:
std::cout << boost::lexical_cast<std::string>(0.0009) << std::endl;
并期望输出为:
0.0009
但输出是:
0.00089999999999999998
g++版本:5.4.0,Boost版本:1.66
我该怎么做才能让它打印出给定的内容。
boost::lexical_cast
不允许您在将浮点数转换为其字符串表示形式时指定精度。来自 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 conventionalstd::stringstream
approach is recommended.
所以你可以使用 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
是双精度浮点文字,假设 IEEE754,值
0.00089999999999999997536692664112933925935067236423492431640625
这就是 boost::lexical_cast<std::string>
所看到的函数参数。 cout
格式化程序中的默认精度设置四舍五入到第 17 位有效数字:
0.00089999999999999998
真的,如果你想要精确的 decimal 精度,那么使用 decimal 类型(Boost 有一个),或者使用整数并自己拼接小数分隔符。但在你的情况下,假设你只是输出没有复杂计算的数字,四舍五入到第 15 位有效数字将产生预期的效果: inject
std::setprecision(15)
进入输出流。
您 可以 实际上覆盖默认精度:
#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::
) 又不灵活(现在所有双打都会以这种方式出现)。
真正的问题
问题是从十进制表示形式转换为二进制表示形式时精度下降。相反,使用十进制浮点数表示:
#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