为什么 1//0.01 == 99 在 Python 中?

Alb*_*ddy 32 python

我想这是一个经典的浮点精度问题,但我试图围绕这个结果,1//0.01在 Python 3.7.5 中运行yields 99

我想这是一个预期的结果,但是有什么方法可以决定何时使用int(1/f)而不是更安全1//f

che*_*ner 24

如果这是与实数的除法,1//0.01则正好是 100。不过,由于它们是浮点近似值,0.01因此略大于 1/100,这意味着商略小于 100。然后是这个 99.something 值到 99。

  • “更安全”没有明确的定义。 (11认同)
  • 这并没有解决“有没有办法决定何时更安全”的部分。 (3认同)
  • @chepner如果“更安全”没有得到很好的定义,那么也许最好要求澄清:/ (3认同)
  • 我很清楚“更安全”意味着“错误不比便宜的袖珍计算器更糟糕” (2认同)

tri*_*cot 10

这个结果的原因就像你说的,并在浮点数学是否被破坏?以及许多其他类似的问答。

当您知道分子和分母的小数位数时,更可靠的方法是先将这些数字相乘,以便将它们视为整数,然后对它们进行整数除法:

所以在你的情况下1//0.01应该首先转换1*100//(0.01*100)为100。

在更极端的情况下,您仍然可以获得“意想不到”的结果。round在执行整数除法之前,可能需要添加对分子和分母的调用:

1 * 100000000000 // round(0.00000000001 * 100000000000)
Run Code Online (Sandbox Code Playgroud)

但是,如果这是关于使用固定小数(钱,美分),那么考虑使用美分作为单位,以便所有算术都可以作为整数算术完成,并且只在执行时转换为/从主要货币单位(美元)输入/输出。

或者,使用小数库,如decimal,它:

...提供对快速正确舍入十进制浮点运算的支持。

from decimal import Decimal
cent = Decimal(1) / Decimal(100) # Contrary to floating point, this is exactly 0.01
print (Decimal(1) // cent) # 100
Run Code Online (Sandbox Code Playgroud)

  • “这显然是 100。” 不一定:如果 .01 不准确,那么 .01 * 100 也不准确。它必须手动“调整”。 (3认同)

myr*_*dio 9

你必须考虑到是什么//floor运营商,因此你首先应该想到,如果你有相同的概率在100下降为99(*)(因为会被操作100 ± epsilonepsilon>0提供的,恰好100.00的机会..0 非常低。)

你实际上可以看到相同的减号,

>>> 1//.01
99.0
>>> -1//.01
-100.0
Run Code Online (Sandbox Code Playgroud)

你应该(不)感到惊讶。

另一方面,int(-1/.01)首先执行除法,然后int()在数字中应用 ,这不是地板而是向 0 的截断!这意味着在那种情况下,

>>> 1/.01
100.0
>>> -1/.01
-100.0
Run Code Online (Sandbox Code Playgroud)

因此,

>>> int(1/.01)
100
>>> int(-1/.01)
-100
Run Code Online (Sandbox Code Playgroud)

不过,四舍五入会给你这个运算符的预期结果,因为同样,这些数字的误差很小。

(*)我不是说概率是一样的,我只是说当你用浮动算术执行这样的计算时,先验的是你得到的估计。


plu*_*ash 7

浮点数不能准确表示大多数十进制数,因此当您键入浮点文字时,您实际上会得到该文字的近似值。近似值可能大于或小于您键入的数字。

您可以通过将浮点数转换为小数或分数来查看浮点数的确切值。

>>> from decimal import Decimal
>>> Decimal(0.01)
Decimal('0.01000000000000000020816681711721685132943093776702880859375')
>>> from fractions import Fractio
>>> Fraction(0.01)
Fraction(5764607523034235, 576460752303423488) 
Run Code Online (Sandbox Code Playgroud)

我们可以使用 Fraction 类型来查找由我们的不精确文字引起的错误。

>>> float((Fraction(1)/Fraction(0.01)) - 100)
-2.0816681711721685e-15
Run Code Online (Sandbox Code Playgroud)

我们还可以通过使用 numpy 中的 nextafter 找出 100 左右的双精度浮点数的粒度。

>>> from numpy import nextafter
>>> nextafter(100,0)-100
-1.4210854715202004e-14
Run Code Online (Sandbox Code Playgroud)

由此我们可以推测最接近的浮点数1/0.01000000000000000020816681711721685132943093776702880859375实际上正好是 100。

1//0.01和之间的区别int(1/0.01)是四舍五入。1//0.01 在一个步骤中将精确结果向下舍入到下一个整数。所以我们得到的结果是 99。

另一方面,int(1/0.01) 分两个阶段舍入,首先将结果舍入到最接近的双精度浮点数(正好是 100),然后将该浮点数向下舍入到下一个整数(即又正好是 100)。