Python:为什么 0.01.as_integer_ratio() return 5764607523034235/576460752303423488

Python: Why does 0.01.as_integer_ratio() return 5764607523034235/576460752303423488

我在 Python 中研究 question 33 of Project Euler 时,我发现了一些我不理解的东西。

问题的答案需要用最常用的术语给出分母。所以我想我会使用 float.as_integer_ratio() 来检查分母是什么。结果是 0.01.as_integer_ratio() returns (5764607523034235, 576460752303423488)0.1.as_integer_ratio() returns (3602879701896397, 36028797018963968) 而不是预期的 1/1001/10 .

为什么会这样?我猜这与这些数字在计算机上的存储方式有关。我也尝试了 Python 的分数库,但这给出了相同的结果。我希望有人能向我解释为什么它会这样。

计算机通常不能用以 10 为底的十进制数进行计算。我不确定量子计算机是否不同,但通常数字在内部计算为以 2 为底。

没有这些知识,这可能是一个令人震惊的时刻:

>>> 0.1 + 0.1 + 0.1 == 0.3
False

这意味着通常使用近似值来很好地表示该数字。由于这些近似值,0.1 + 0.1 + 0.1 不是 0.3

所以一个简单的 0.1(基数 10)变成 0.0001 1001 1001 1001...(基数 2,无穷无尽)。但是为了拯救和摆脱近似值的分数! float.as_integer_ratio() 想要准确:

Return a pair of integers whose ratio is exactly equal to the original float and with a positive denominator.

(参见 Python documentation,强调我的。)

所以该方法是使用一种算法来计算确切的比率,例如来自 0.1,算法可以找到的最佳数字是 360287970189639736028797018963968。看起来数字不错,因为分数库得到相同的结果(如你所说)。

顺便说一句:如果您计算的是十进制数,那么以 10 为底的一切都很好,您也可以在以 2 为底的情况下处理,例如0.5(=0.1 到基数 2):

>>> 0.5.as_integer_ratio()
(1, 2)

如果您想阅读更多内容,Python tutorials.

中还有一个包含许多详细信息和更多链接的好站点

正如 colidyre 所提到的,问题在于浮点表示的不准确性。您可以使用分数库中的 limit_denominator method 来获得正确的结果。

>>> from fractions import Fraction
>>> Fraction(0.01).limit_denominator(100000)
1/100