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

Blatant floating point error in C++ program

我正在为 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

那么,怎么处理呢? (Window 7 及更高版本,VS 2013)

...要使用两个双打,一个用于高值,一个用于低值? 就像,而不是使用 d 来使用 d1d2?

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

存储

阅读 Number of Digits Required For Round-Trip Conversions 了解更多详情。

好吧,您将面对浮点数的狂野西部!不要相信任何人,不要抱太大希望,把手放在枪上。

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

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

嘿,我在第二种情况下的小数部分在哪里?它消失了!报警!哦,等等,它只是不适合... 这就是 diff 给出零的原因:尾数太大以至于无法存储尾部(实际差异所在的位置)。只要其余数字相同,我们就有零差异。

经过仔细比较,你还发现了另外一件事:打印出来的值和赋值值很接近,但是还是有一点不同。这是因为尾数只是 2 的幂之和。因此,为了表示该值,计算机必须将分配的值四舍五入到最接近的 binary-compatible 一个。有时这是另一种痛苦,您不应该通过相等运算符比较 floating-point 数字,只需评估差异并将其与预期精度的预期增量进行比较。