17
double val = 0.1;
std::stringstream ss;
ss << val;
std::string strVal= ss.str();

在 Visual Studio 调试器val中,值为 0.10000000000000001(因为无法表示 0.1)。当val使用 stringstream 转换时,strVal等于"0.1". 但是,当使用 boost::lexical_cast 时,结果strVal"0.10000000000000001".

另一个例子如下:

double val = 12.12305000012;

在 Visual Studio 下val显示为 12.123050000119999,使用 stringstream 和默认精度 (6) 它变为 12.1231。我真的不明白为什么它不是 12.12305(...)。

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

谢谢。

4

4 回答 4

19

您可以更改 a 的浮点精度,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

注意数字是如何在适当的时候四舍五入的。

于 2012-10-15T11:55:10.230 回答
16
于 2014-12-08T10:51:48.073 回答
5

您必须考虑两个问题。第一个是精度参数,默认为 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
于 2012-10-15T13:07:15.713 回答
4

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

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

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

附录
1.0/3.0 的值出现了更好的演示。使用默认精度,您将获得"0.333333". 这不是双精度 1/3 的字符串等价物。使用setprecision(16)生成字符串"0.3333333333333333";精度为 17 产量"0.33333333333333331"

于 2012-10-15T11:43:49.427 回答