问题描述
任何人都可以解释模运算符在Python中的工作方式吗?我不明白为什么3.5 % 0.1 = 0.1
.
Can anyone explain how the modulo operator works in Python?I cannot understand why 3.5 % 0.1 = 0.1
.
推荐答案
实际上,3.5 % 0.1
是0.1
并不是事实.您可以很容易地对此进行测试:
Actually, it's not true that 3.5 % 0.1
is 0.1
. You can test this very easily:
>>> print(3.5 % 0.1)
0.1
>>> print(3.5 % 0.1 == 0.1)
False
实际上,在大多数系统上,3.5 % 0.1
是0.099999999999999811
.但是,在某些版本的Python上,str(0.099999999999999811)
是0.1
:
In actuality, on most systems, 3.5 % 0.1
is 0.099999999999999811
. But, on some versions of Python, str(0.099999999999999811)
is 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.1
是0.099999999999999811
而不是0.0
.这是由于通常的浮点舍入问题.如果您还没有阅读每位计算机科学家应该了解的浮动内容-点算术,您应该-至少至少是维基百科的摘要特殊的问题.
Now, you're probably wondering why 3.5 % 0.1
is 0.099999999999999811
instead of 0.0
. That's because of the usual floating point rounding issues. If you haven't read What Every Computer Scientist Should Know About Floating-Point Arithmetic, you should—or at least the brief Wikipedia summary of this particular issue.
还请注意,3.5/0.1
不是34
,它是35
.因此,3.5/0.1 * 0.1 + 3.5%0.1
是3.5999999999999996
,甚至还没有 close 到3.5
.这对于模数的定义非常重要,在Python和几乎所有其他编程语言中都是错误的.
Note also that 3.5/0.1
is not 34
, it's 35
. So, 3.5/0.1 * 0.1 + 3.5%0.1
is 3.5999999999999996
, which isn't even close to 3.5
. This is pretty much fundamental to the definition of modulus, and it's wrong in Python, and just about every other programming language.
但是Python 3在那里救了出来.大多数了解//
的人都知道这是在整数之间进行整数除法"的方式,但没有意识到这是在 any 类型之间进行模数兼容除法的方式. 3.5//0.1
是34.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)
,但是由于舍入错误,您不能拥有它.
But Python 3 comes to the rescue there. Most people who know about //
know that it's how you do "integer division" between integers, but don't realize that it's how you do modulus-compatible division between any types. 3.5//0.1
is 34.0
, so 3.5//0.1 * 0.1 + 3.5%0.1
is (at least within a small rounding error of) 3.5
. This has been backported to 2.x, so (depending on your exact version and platform) you may be able to rely on this. And, if not, you can use divmod(3.5, 0.1)
, which returns (within rounding error) (34.0, 0.09999999999999981)
all the way back into the mists of time. Of course you still expected this to be (35.0, 0.0)
, not (34.0, almost-0.1)
, but you can't have that because of rounding errors.
如果您正在寻找快速解决方案,请考虑使用 Decimal
类型:
If you're looking for a quick fix, consider using the Decimal
type:
>>> 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中不能无限表示时,您仍然必须处理舍入错误-但舍入错误会更好地与情况对齐人们的直觉期望会出现问题. (与float
相比,Decimal
还有其他优点,因为您可以指定显式精度,跟踪有效数字等,并且在从2.4到3.3的所有Python版本中它实际上都是相同的,而有关float
的详细信息在同一时间两次更改.只是因为它不完美,因为这是不可能的.)但是当您事先知道您的数字都可以精确地表示为以10为底的数字时,它们不需要比精度还要多的数字您已经配置了,它将正常工作.
This isn't a magical panacea — for example, you'll still have to deal with rounding error whenever the exact value of an operation isn't finitely representable in base 10 - but the rounding errors line up better with the cases human intuition expects to be problematic. (There are also advantages to Decimal
over float
in that you can specify explicit precisions, track significant digits, etc., and in that it's actually the same in all Python versions from 2.4 to 3.3, while details about float
have changed twice in the same time. It's just that it's not perfect, because that would be impossible.) But when you know in advance that your numbers are all exactly representable in base 10, and they don't need more digits than the precision you've configured, it will work.
这篇关于浮点数的Python模的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!