双重和字符串流格式

double and stringstream formatting

本文关键字:格式 字符串      更新时间:2023-10-16
double val = 0.1;
std::stringstream ss;
ss << val;
std::string strVal= ss.str();

在Visual Studio调试器中,val的值为0.10000000000000001(因为无法表示0.1)。当使用字符串流转换val时,strVal等于"0.1"。但是,当使用boost::lexical_cast时,得到的strVal"0.10000000000000001"

另一个例子如下:

double val = 12.12305000012;

在visual studio下,val显示为12.12305000011999,使用字符串流和默认精度(6),它变为12.1231。我真的不明白为什么不是12.12305(…)。

是否有默认精度,或者字符串流是否有特定的算法来转换无法精确表示的双值?

谢谢。

您可以更改stringstream的浮点精度,如下所示:

double num = 2.25149;
std::stringstream ss(stringstream::in | stringstream::out);
ss << std::setprecision(5) << num << endl;
ss << std::setprecision(4) << num << endl;

输出:

2.2515
2.251

请注意,在适当的情况下,数字也是四舍五入的。

对于任何获得"error: ‘setprecision’ is not a member of ‘std’"的人,您必须使用#include <iomanip>,否则setprecision(17)将不起作用!

您必须考虑两个问题。第一是精度参数,默认为6(但您可以将其设置为类似)。第二个是这个参数的含义,这取决于您正在使用的格式选项:如果您使用的是固定格式或科学格式格式,则表示小数后的位数(在转弯对两种格式);但是,如果使用默认精度(ss.setf( std::ios_base::fmtflags(), std::ios_base::formatfield ),则表示输出中位数,无论输出是否实际上是用科学的或固定的记数法格式化的。这就解释了例如,为什么您的显示器是12.1231;您同时使用默认精度和默认格式化。

你可能想尝试以下不同值的方法(也许不同精度):

std::cout.setf( std::ios_base::fmtflags(), std::ios_base::floatfield );
std::cout << "default:    " << value[i] << std::endl;
std::cout.setf( std::ios_base::fixed, std::ios_base::floatfield );
std::cout << "fixed:      " << value[i] << std::endl;
std::cout.setf( std::ios_base::scientific, std::ios_base::floatfield );
std::cout << "scientific: " << value[i] << std::endl;

看到实际输出可能比任何详细描述都更清楚:

default:    0.1
fixed:      0.100000
scientific: 1.000000e-01

问题发生在流插入ss << 0.1;,而不是转换为字符串。如果你想要非默认精度,你需要在插入双精度之前指定:

ss << std::setprecision(17) << val;

在我的电脑上,如果我只使用setprecision(16),我仍然会得到"0.1",而不是"0.10000000000000001"。我需要一个(稍微伪造的)17的精度才能看到最后的1。

附录
如果值为1.0/3.0,则会出现更好的演示。使用默认精度,可以得到"0.333333"的字符串表示。这不是相当于双精度1/3的字符串。使用CCD_ 20使得字符串CCD_;精度为17得到CCD_ 22。