程序中明显的浮点错误C++

Blatant floating point error in C++ program

本文关键字:错误 C++ 程序      更新时间:2023-10-16

我正在为double变量分配一个双精度文字。 变量的值被截断,否则我不明白为什么,例如diff差为 0.0。

很抱歉setprecision的代码重复,但我真的很生气。

#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
int main()
{
long double d = 1300010000000000000144.5700788999;
long double d1 = 1300010000000000000000.0;
long double diff = d - d1; // shall be 144.5700788999!!!
long double d2 = 0.5700788999;
std::cout << "d = " << std::fixed << std::setprecision(std::numeric_limits<long double>::digits10 + 1) << d << 'n';
std::cout << "d1 = " << std::fixed << std::setprecision(std::numeric_limits<long double>::digits10 + 1) << d1 << 'n';
std::cout << "d - d1 = " << std::fixed << std::setprecision(std::numeric_limits<long double>::digits10 + 1) << diff << 'n';
std::cout << "d2 = " << std::fixed << std::setprecision(std::numeric_limits<long double>::digits10 + 1) << d2 << 'n';
}

这是输出:

d = 1300009999999999900000.0000000000000000
d1 = 1300009999999999900000.0000000000000000
d - d1 = 0.0000000000000000
d2 = 0.5700788999000001

我希望diff144.5700788999但这很0.0

那么,该如何应对呢?(窗口 7 及更高版本,VS 2013)

。使用两个双精度,一个用于高值,一个用于低值? 就像,而是使用d来使用d1d2

80 位long double(不确定其在 MSPS 中的大小)可以存储大约 18 个有效的十进制数字而不会损失精度。1300010000000000000144.5700788999有 32 个有效的十进制数字,不能完全按照long double存储。

有关更多详细信息,请参阅往返转换所需的位数。

好吧,你面对的是浮点的狂野西部!不要相信任何人,不要期望太多,把手放在你的枪上。

问题是:浮点表示是一个分裂。给定的字节量用于存储两个部分,尾数值和第十次方(当然是简化的描述,但它足以满足我们在这里的需求)。一旦你的值太大而无法放入尾数,计算机该怎么办?它必须将其余部分带到字节的另一部分(就像大数学库所做的那样),或者只是四舍五入到最接近的值。让我展示一下:

d2 =                      0.5700788999; // shows                      0.5700788999000001
d2 = 1300010000000000000000.5700788999; // shows 1300009999999999934464.0000000000000000000

嘿,我在第二种情况下的小数部分在哪里?不见了!报警!哦,等等,它只是不适合...这就是为什么 diff 给出零的原因:螳螂是如此之大,以至于尾部(实际差异所在)无法存储。一旦其余数字相同,我们的差异为零。

仔细比较后,您可以发现另一件事:打印值接近分配的值,但有点不同。这是因为尾数只是 2 的幂之和。因此,为了表示值,计算机必须将分配的值舍入到最接近二进制兼容的值。这有时是另一种痛苦,您不应该通过相等运算符比较浮点数,只需评估差异并将其与预期精度的预期增量进行比较。