Python 如何记住用于指定浮点数的小数位数?

How does Python remember the number of decimal places one used to specify a float?

今天有人向我指出 0.99 不能用浮点数表示:

num = 0.99
print('{0:.20f}'.format(num))

打印 0.98999999999999999112。我对这个概念很好。

那么 python 是怎么知道这样做的:

num = 0.99
print(num)

打印 0.99.

不记得了。它正在查看它获得的值并决定呈现它的最佳方式,它认为在这种情况下是 0.99,因为该值尽可能接近 0.99。

如果你 print(0.98999999999999999112) 它会显示 0.99,即使这不是你用来指定它的小数位数。

How does Python remember the number of decimal places one used to specify a float?

没有。试试这个:

num = 0.990
print(num)

请注意,这也会输出 0.99,而不是 0.990

我不能专门针对 print 函数说话,但在具有 IEEE-754 双精度二进制浮点数的环境中使用仅输出所需数字的算法很常见将该数字与其最接近的“可表示”邻居区分开来。但它比表面上看起来要复杂得多。参见 this paper on number rounding for details (associated code here and here)。

Sam Mason 提供了一些与此相关的重要链接:

  • 来自Floating Point Arithmetic: Issues and Limitations

    这证实了上面“最接近可表示”的事情。它首先描述了以 10 为基数的问题,即您无法准确表示三分之一 (1/3)。 0.3 接近,0.33 更接近,0.333 更接近,但实际上 1/3 是一个无限重复的系列,0.3 之后永远是 3。同样,二进制浮点数(将数字存储为以 2 为底的分数而不是以 10 为底的分数)不能精确表示 0.1(例如),就像以 10 为底的 1/3 它是一个无限重复的数字系列在基数 2 中,其他任何东西都是近似值。然后继续:

    In the same way, no matter how many base 2 digits you’re willing to use, the decimal value 0.1 cannot be represented exactly as a base 2 fraction. In base 2, 1/10 is the infinitely repeating fraction

    0.0001100110011001100110011001100110011001100110011... Stop at any finite number of bits, and you get an approximation. On most machines today, floats are approximated using a binary fraction with the numerator using the first 53 bits starting with the most significant bit and with the denominator as a power of two. In the case of 1/10, the binary fraction is 3602879701896397 / 2 ** 55 which is close to but not exactly equal to the true value of 1/10.

    Many users are not aware of the approximation because of the way values are displayed. Python only prints a decimal approximation to the true decimal value of the binary approximation stored by the machine. On most machines, if Python were to print the true decimal value of the binary approximation stored for 0.1, it would have to display

    >>> 0.1

    0.1000000000000000055511151231257827021181583404541015625

    That is more digits than most people find useful, so Python keeps the number of digits manageable by displaying a rounded value instead

    >>> 1 / 10

    0.1

    Just remember, even though the printed result looks like the exact value of 1/10, the actual stored value is the nearest representable binary fraction.

  • The code for it in CPython

  • An issue discussing it 在问题列表中