我是python的新手,在Mac上使用Python3.5.1时发现了一个令人困惑的结果,我只是在终端中运行了这个命令
1 // 0.05
然而,它在我的屏幕上打印了19.0。从我的观点来看,它应该是20.有人可以解释这里发生了什么吗?我已经知道'//'类似于math.floor()函数。但我仍然无法接受这一点。
答案 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.0
(1 / 0.05
文字float
,而不是精确的小数部分0.05)实际上 > 20,但0.05
类型本身无法表示差异。
此时你可能会想“那又怎么样?我不在乎Python正在给出一个错误值的正确倒数。我想知道如何在第一时间获得正确的价值。“答案就是:
decimal.Decimal('0.05')
(并且不要忘记引号!)fractions.Fraction('0.05')
(当然,你也可以使用分子 - 分母参数作为float
,如果你需要处理像1/3这样的非小数部分,这很有用。)