为什么1 // 0.05在python中导致19.0?

时间:2016-03-09 16:47:57

标签: python floating-accuracy

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

    1 // 0.05

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

3 个答案:

答案 0 :(得分:6)

因为Python浮点文字0.05表示的数字略大于数学值0.05。

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

//是分部,意味着结果是最大整数n,使得除数的n倍小于或等于被除数。由于0.050000000000000000000277555756156289135105907917022705078125的20倍大于1,这意味着正确的结果是19。

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

答案 1 :(得分:3)

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

但是,所有浮点值在存储时都会舍入为double,但计算结果会更高。在这种情况下,1//0.05执行的楼层操作似乎是以完全内部精度完成的,因此它是向下舍入的。

答案 2 :(得分:1)

正如先前的回答者已经正确指出的那样,0.05 = 1/20的分数不能用有限数量的基数 - 2位数来精确表示。它适用于重复分数0.0000 1100 1100 1100 ...(非常像1/3 = 0.333 ......在熟悉的基数为10)。

但这对你的问题并不是一个完整的答案,因为这里还有一点古怪:

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

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

但是1 // 0.05怎么回来19? Isn&#t; t a // b应该与math.floor(a /b)相同吗?为什么///之间的不一致?

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

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

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

准确地说,72057594037927936/3602879701896397 = 19.999999999999998889776975374843521206126552300723564152465244707437044687 ...

因此,//divmod会看到一个19的整数商。剩余部分适用于0.04999999999999994726440633030506432987749576568603515625,它被舍入为0.04999999999999995显示。因此,鉴于divmod的原始错误值,上面的0.05答案实际上对53位精度有好处。

但是/呢?那么,真商72057594037927936/3602879701896397不能表示为float,因此必须舍入为20-2**-48(误差约为2.44e-15)或最高为{ {1}}(大约1.11e-15的错误)。 Python正确地选择了更准确的选择20.0

因此,似乎Python的浮点除法在内部以足够高的精度完成,以便知道20.01 / 0.05文字float ,而不是精确的小数部分0.05)实际上 > 20,但0.05类型本身无法表示差异。

此时你可能会想“那又怎么样?我不在乎Python正在给出一个错误值的正确倒数。我想知道如何在第一时间获得正确的价值。“答案就是: