【发布时间】:2016-10-12 07:01:20
【问题描述】:
在链接我之前 Is floating point math broken? - 请先阅读问题。我知道这是如何工作的。这个问题是针对我发现的两个数字的(嗯,大概存在更多这样的对,但我希望这个特定的行为得到解释)。
我有两个浮点常量:1.9 和 1.1。使用 Python,我将它们乘以它们的倒数并得到以下结果:
>>> x = 1.1
>>> y = 1.9
>>> print("%.55f" % x)
1.1000000000000000888178419700125232338905334472656250000
>>> print("%.55f" % y)
1.8999999999999999111821580299874767661094665527343750000
>>> print("%.55f" % (1/x))
0.9090909090909090606302811465866398066282272338867187500
>>> print("%.55f" % (1/y))
0.5263157894736841813099204046011436730623245239257812500
>>> print("%.55f" % ((1/x) * x))
1.0000000000000000000000000000000000000000000000000000000
>>> print("%.55f" % ((1/y) * y))
0.9999999999999998889776975374843459576368331909179687500
我当然知道在硬件中实现的浮点运算存在问题,但我不明白为什么这些数字表现出如此不同的行为。考虑它们的倒数;它们的确切结果如下(使用 WolframAlpha 计算,为简洁起见省略了后面的数字):
-
1/x:0.909090909090909017505915727262383419481191148103102677263... -
1/y:0.526315789473684235129596113576877392185605155259237553584...
很明显,我的硬件计算的倒数是正确的,直到两个数字的第 15-16 位十进制数字左右;那里没有区别。还有什么不同的? (1/x) * x 怎么可能完全 1,最后没有任何“垃圾”?
为了完整起见,我或许应该提一下,我使用的是 x86 PC,所以这都是 64 位 IEEE 754 算法:
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
【问题讨论】:
-
我理解您的反对意见,但首先:我已阅读您的问题 :) 您可能还应该添加一个标签来指定您使用的编程语言(可能是 python-3.something ?)。
-
但是您想知道为什么 (1/z)*z 对于不同的 z 是不同的这一事实证明您没有完全理解浮点数,抱歉。跨度>
-
@MarcusMüller 事实上,我还没有完全理解这个主题——否则就没有问题要问了!但我认为,某个特定问题已在 SO 的其他地方部分涵盖这一事实并不意味着与之相关的新问题以及无法开始询问其他问题。
-
任何略小于一和一的数和略大于一的数都是(1/z)*z的可能结果,这正是有限长度算术的本质。所以你可能会随意选择所有符合 IEEE754 的硬件和软件实现(没有单一的“正确”方式),并尝试直到你得到准确的结果。因为我不知道你使用的是哪个 FPU/CPU,或者你的脚本语言使用了哪些浮点指令并且没有参与其中任何一个的实现,“它是特定于实现的”是我能做的最好的
标签: floating-point numerical floating-point-conversion