一尘不染

Python-浮点数的Python模

python

谁能解释模运算符在Python中如何工作?我不明白为什么3.5 % 0.1 = 0.1


阅读 412

收藏
2020-02-23

共1个答案

一尘不染

其实,这是不正确的3.5 % 0.1是0.1。你可以很容易地测试一下:

>>> print(3.5 % 0.1)
0.1
>>> print(3.5 % 0.1 == 0.1)
False

实际上,在大多数系统上3.5 % 0.10.099999999999999811。但是,在某些版本的Python上str(0.099999999999999811)0.1

>>> 3.5 % 0.1
0.099999999999999811
>>> repr(3.5 % 0.1)
'0.099999999999999811'
>>> str(3.5 % 0.1)
'0.1'

现在,你可能想知道为什么3.5 % 0.10.099999999999999811而不是0.0。这是由于通常的浮点舍入问题。如果你还没有阅读每位计算机科学家应该知道的有关浮点运算的知识,那么你应该-至少是Wikipedia对此问题的简要概述。

还需要注意的是3.5/0.1不是34,它的35。那么,3.5/0.1 * 0.1 + 3.5%0.1是3.5999999999999996,这是不甚至接近到3.5。这对于模数的定义非常重要,在Python和几乎所有其他编程语言中都是错误的。

但是Python 3在那里抢救了。大多数了解的人都知道//这是你如何在整数之间进行“整数除法”,但没有意识到这是你如何在任何类型之间进行模数兼容的除法。3.5//0.134.0,因此3.5//0.1 * 0.1 + 3.5%0.1是(至少内的一个小的舍入误差)3.5。它已被反向移植到2.x,因此(取决于你的确切版本和平台),你也许可以依靠此。而且,如果没有,则可以使用divmod(3.5, 0.1),它返回(在舍入误差内)(34.0, 0.09999999999999981)一直回到时间的迷雾中。当然,你仍然希望这是(35.0, 0.0),而不是(34.0, almost-0.1),但是由于舍入错误,你不能拥有它。

如果你正在寻找快速修复,请考虑使用以下Decimal类型:

>>> from decimal import Decimal
>>> Decimal('3.5') % Decimal('0.1')
Decimal('0.0')
>>> print(Decimal('3.5') % Decimal('0.1'))
0.0
>>> (Decimal(7)/2) % (Decimal(1)/10)
Decimal('0.0')

这不是魔术般的灵丹妙药-例如,每当操作的确切值在基数10中不能有限地表示时,你仍然必须处理舍入错误-但是舍入错误与人类直觉期望的情况更好地对齐有问题。(Decimalover的另一个优点float是,你可以指定显式精度,跟踪有效数字等,并且在从2.4到3.3的所有Python版本中实际上都是相同的,而有关详细信息同时float已更改了两次。但是,当你事先知道所有数字都可以精确地以10为基数表示,并且它们不需要的位数比你配置的精度高时,它就会起作用。

2020-02-23