为什么 1 // 0.05 在 python 中得到 19.0?

why 1 // 0.05 results in 19.0 in python?

我是 python 的新手,在我的 mac 上使用 Python3.5.1 时,我发现了一个令人困惑的结果,我只是在我的 运行 中使用了这个命令航站楼

    1 // 0.05

但是,它在我的屏幕上打印了 19.0。从我的角度来看,它应该是 20。有人可以解释这里发生了什么吗?我已经知道 '//' 类似于 math.floor() 函数。但是我仍然无法理解这一点。

0.05 不能用浮点数精确表示。 "%0.20f" % 0.05 表明 0.05 存储为比精确值稍大的值:

>>> print "%0.20f" % 0.05
0.05000000000000000278

另一方面,1/0.05 看起来正好是 20:

>>> print "%0.20f" % (1/0.05)
20.00000000000000000000

然而,所有浮点值在存储时都四舍五入为双倍,但计算精度更高。在这种情况下,1//0.05 执行的 floor 操作似乎是在完全内部精度下完成的,因此它被向下舍入。

因为 Python 浮点字面值 0.05 表示一个比数学值 0.05 稍大的数字。

>>> '%.60f' % 0.05
'0.050000000000000002775557561562891351059079170227050781250000'

//是floor除法,意思是结果是最大整数n使得n乘以除数小于等于被除数。由于 20 次 0.05000000000000000277555756156289135105907917022705078125 大于 1,这意味着正确的结果是 19.

至于为什么 Python 文字 0.05 不代表数字 0.05,以及许多其他关于浮点数的事情,请参阅 What Every Computer Scientist Should Know About Floating-Point Arithmetic

正如前面的回答者正确指出的那样,分数 0.05 = 1/20 不能用有限的两位数来精确表示。它计算出重复分数 0.0000 1100 1100 1100...(很像 1/3 = 0.333... 在熟悉的十进制中)。

但这并不是您问题的完整答案,因为这里还有一些奇怪的地方:

>>> 1 / 0.05
20.0
>>> 1 // 0.05
19.0

使用“真除法”运算符 / 恰好给出了预期的答案 20.0。你在这里很幸运:除法中的舍入误差正好抵消了表示值 0.05 本身的误差。

但是1 // 0.05 returns 19怎么来的? a // b 不应该和 math.floor(a /b) 一样吗?为什么 /// 不一致?

注意divmod函数与//运算符一致:

>>> divmod(1, 0.05)
(19.0, 0.04999999999999995)

可以通过使用精确的有理算术计算浮点除法来解释此行为。当您在 Python 中写入文字 0.05 时(在符合 IEEE 754 的平台上),表示的实际值为 3602879701896397 / 72057594037927936 = 0.05000000000000000277555756156289135105907917028127550这个值恰好比预期的 0.05 略 ,这意味着它的倒数将略

准确地说,72057594037927936 / 3602879701896397 = 19.9999999999999988897769753748435212061265523007235641524652447074370446187]...[=4

因此,//divmod看到整数商19。余数为0.04999999999999994726440633030506432987749576568603515625,四舍五入显示为0.04999999999999995。因此,考虑到 0.05.

的原始错误值,上面的 divmod 答案实际上可以达到 53 位精度

但是 / 呢?好吧,真正的商 72057594037927936 / 3602879701896397 不能表示为 float,因此它必须四舍五入,要么向下舍入到 20-2**-48(大约 2.44e-15 的误差)要么向上舍入 20.0(大约 1.11e-15 的错误)。 Python 正确地选择了更准确的选择,20.0

所以,似乎 Python 的浮点除法在内部以足够高的精度完成 1 / 0.05(即 float 文字 0.05 ,不是精确的小数0.05),其实比20少,但是float类型本身是无法表示差异的

此时你可能会想“那又怎样?我不在乎 Python 给出了错误值的正确倒数。我首先想知道如何获得正确的值。”答案是: