我爱FP
;每当我想得到它时,我都知道对此一无所知:)
This是我不理解的示例。我将相同的数字(0.1
)相加8倍,然后打印出sum和“original”的结果:
std::cout.precision(100);
int numIteration = 8;
double step = 0.1;
double sum = 0.0;
for(int i = 0; i < numIteration; i++) {
sum += step;
}
std::cout << "orig stored as " << numIteration / 10.0 << std::endl;
std::cout << " sum stored as " << sum << std::endl;
0.1
存储为0.1000000000000000055511151231257827021181583404541015625
,我希望在8和之后,它将存储为更大或等于0.8
的形式,后者存储为0.8000000000000000444089209850062616169452667236328125
。但是结果震惊了我。实际上,在8和之后,结果是
0.79999999999999993338661852249060757458209991455078125
,它较小。另外,如果我检查两者的二进制输出,我可以看到总和比“原始”“高”:
0.8 stored as binary 0 01111111110 1001100110011001100110011001100110011001100110011001 // smaller
sum stored as binary 0 01111111110 1001100110011001100110011001100110011001100110011010 // higher
但是
0.79999999999999993338661852249060757458209991455078125
<0.8000000000000000444089209850062616169452667236328125
。你能照耀我吗?
编辑:对不起,我在复制/粘贴二进制文件时出错。他们是正确的。
最佳答案
使用IEEE floating-point rounding会在每个算术运算之后发生。而且舍入可能会上升或下降。
如果在每次迭代中都打印sum
的值,则应该看到:
sum is 0.1000000000000000055511151231257827021181583404541015625
sum is 0.200000000000000011102230246251565404236316680908203125
sum is 0.3000000000000000444089209850062616169452667236328125
sum is 0.40000000000000002220446049250313080847263336181640625
sum is 0.5
sum is 0.59999999999999997779553950749686919152736663818359375
sum is 0.6999999999999999555910790149937383830547332763671875
sum is 0.79999999999999993338661852249060757458209991455078125
您假设四舍五入只会增加。但是,由于IEEE 754中默认的舍入模式是“舍入到最接近,连成偶数”,因此在每次迭代时都选择最接近的二进制可表示值,因此结果不必大于
0.8
。另一方面
std::cout << 0.1 * 8.0 << std::endl;
会产生预期的
0.8000000000000000444089209850062616169452667236328125
更新:如注释中提到的@Evg,可以使用
std::fesetround
更改浮点舍入方向。关于c++ - 尾数较高的fp如何代表较小的数字?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52146170/