谷歌计算器故障,可能会浮动双是一个可能的原因吗?
-
09-06-2019 - |
题
我这样做只是为了好玩(所以,不完全是一个问题,我可以看到已经发生了向下修改)但是,代替谷歌的新发现 无力 去做 数学 正确地 (核实!根据谷歌500,000,000,000,002 - 500,000,000,000,001 = 0),我想我会尝试在C中执行以下操作来运行一些理论。
int main()
{
char* a = "399999999999999";
char* b = "399999999999998";
float da = atof(a);
float db = atof(b);
printf("%s - %s = %f\n", a, b, da-db);
a = "500000000000002";
b = "500000000000001";
da = atof(a);
db = atof(b);
printf("%s - %s = %f\n", a, b, da-db);
}
当你运行这个程序时,你会得到以下信息
399999999999999 - 399999999999998 = 0.000000
500000000000002 - 500000000000001 = 0.000000
看起来Google正在使用简单的32位浮点精度(这里的错误),如果你在上面的代码中将float切换为double,你就可以解决问题!会是这样吗?
/mp
解决方案
在 C# 中,尝试 (double.maxvalue == (double.maxvalue - 100)) ,你会得到 true ...
但这就是它应该的样子:
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
考虑一下,您有 64 位表示大于 2^64 (double.maxvalue) 的数字,因此预计会出现不准确的情况。
其他提示
有关更多此类愚蠢内容,请参阅这篇有关 Windows 计算器的好文章。
Calc的内部 - 算术引擎 - 完全抛弃并从头开始重写。标准的IEEE浮点库被任意精确的算术库代替。这是在人们不断撰写有关Calc无法正确执行小数算术的HA -HA文章之后完成的,例如计算10.21-10.2导致0.0100000000000016。
看起来Google正在使用简单的32位浮点精度(这里的错误),如果你在上面的代码中将float切换为double,你就可以解决问题!会是这样吗?
不,你只是推迟这个问题。双打仍然表现出同样的问题,只是数量更大。
@玉宝
考虑一下,您有 64 位表示大于 2^64 (double.maxvalue) 的数字,因此预计会出现不准确的情况。
2^64 不是 double 的最大值。2^64 是 double(或任何其他 64 位类型)可以保存的唯一值的数量。 Double.MaxValue
等于 1.79769313486232e308。
浮点数的不准确性并非来自于表示大于的值 Double.MaxValue
(这是不可能的,排除 Double.PositiveInfinity
)。这是因为所需的值范围太大,无法适应数据类型。所以我们放弃精度来换取更大的有效范围。从本质上讲,我们正在删除有效数字以换取更大的指数范围。
@DrPizza
甚至不;IEEE 编码对相同值使用多种编码。具体来说,NaN 由全位 1 的指数表示,然后尾数为任何非零值。因此,双打有 252 个 NaN,单打有 223 个 NaN。
真的。我没有考虑重复的编码。实际上有2个52-1 NaN 表示双打,223不过,对于单打来说 -1 NaN。:p
2^64 不是 double 的最大值。2^64 是 double(或任何其他 64 位类型)可以保存的唯一值的数量。Double.MaxValue 等于 1.79769313486232e308。
甚至不;IEEE 编码对相同值使用多种编码。具体来说,NaN用全位-1的指数来表示,然后 任何 尾数的非零值。因此,有 252 双打的 NaN,223 单打的 NaN。
真的。我没有考虑重复的编码。不过,双打实际上有 252-1 个 NaN,单打有 223-1 个 NaN。:p
哦,忘了减去无穷大。
我了解到的这个问题的粗略估计版本是,32 位浮点数为您提供 5 位精度,64 位浮点数为您提供 15 位精度。当然,这会根据浮点数的编码方式而有所不同,但这是一个非常好的起点。