python 具有负值的模运算 - 奇怪的事情?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 19:26:14  来源:igfitidea点击:

Modulus operation with negatives values - weird thing?

pythonmathmodulo

提问by lurks

Can you please tell me how much is (-2) % 5? According to my Python interpreter is 3, but do you have a wise explanation for this?

你能告诉我多少钱(-2) % 5吗?根据我的 Python 解释器是 3,但是您对此有明智的解释吗?

I've read that in some languages the result can be machine-dependent, but I'm not sure though.

我读过在某些语言中结果可能依赖于机器,但我不确定。

采纳答案by Konrad Rudolph

By the way: most programming languages would disagree with Python and give the result -2. Depending on the interpretation of modulus this is correct. However, the most agreed-upon mathematical definition states that the modulus of aand bis the (strictly positive) rest rof the division of a/ b. More precisely, 0 <= r< bby definition.

顺便说一句:大多数编程语言不同意 Python 并给出结果-2。根据对模量的解释,这是正确的。然而,最一致的数学定义指出ab的模数是a/ b除法的(严格为正的)其余r。更准确地说,0 <= r< b根据定义。

回答by martinatime

The result of the modulus operation on negatives seems to be programming language dependent and here is a listing http://en.wikipedia.org/wiki/Modulo_operation

对负数进行模运算的结果似乎取决于编程语言,这里是一个列表http://en.wikipedia.org/wiki/Modulo_operation

回答by Tnilsson

Your Python interpreter is correct. One (stupid) way of calculating a modulus is to subtract or add the modulus until the resulting value is between 0 and (modulus ? 1).

你的 Python 解释器是正确的。计算模数的一种(愚蠢的)方法是减去或添加模数,直到结果值介于 0 和(模数?1)之间。

e.g.: 13 mod 5 = (13 ? 5) mod 5 = (13 ? 10) mod 5 = 3

例如:13 mod 5 = (13 ? 5) mod 5 = (13 ? 10) mod 5 = 3

or in your case: ?2 mod 5 = (?2 + 5) mod 5 = 3

或者在你的情况下:?2 mod 5 = (?2 + 5) mod 5 = 3

回答by tzot

Like the documentation says in Binary arithmetic operations, Python assures that:

就像二进制算术运算中的文档所说的那样,Python 保证:

The integer division and modulo operators are connected by the following identity: x == (x/y)*y + (x%y). Integer division and modulo are also connected with the built-in function divmod(): divmod(x, y) == (x/y, x%y).

整数除法和模运算符通过以下标识连接:x == (x/y)*y + (x%y). 整数除法和取模也与内置函数 divmod(): 相关联divmod(x, y) == (x/y, x%y)

And truly,

真的,

>>> divmod(-2, 5)
(-1, 3).

Another way to visualize the uniformity of this method is to calculate divmodfor a small sequence of numbers:

另一种可视化此方法一致性的方法是计算divmod一个小的数字序列:

>>> for number in xrange(-10, 10):
...     print divmod(number, 5)
...
(-2, 0)
(-2, 1)
(-2, 2)
(-2, 3)
(-2, 4)
(-1, 0)
(-1, 1)
(-1, 2)
(-1, 3)
(-1, 4)
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(1, 4)

回答by Matt Sheppard

Well, 0 % 5 should be 0, right?

嗯,0 % 5 应该是 0,对吧?

-1 % 5 should be 4 because that's the next allowed digit going in the reverse direction (i.e., it can't be 5, since that's out of range).

-1 % 5 应该是 4,因为这是下一个允许的相反方向的数字(即它不能是 5,因为它超出了范围)。

And following along by that logic, -2 must be 3.

按照这个逻辑,-2 必须是 3。

The easiest way to think of how it will work is that you keep adding or subtracting 5 until the number falls between 0 (inclusive) and 5 (exclusive).

考虑它如何工作的最简单方法是不断加或减 5,直到数字介于 0(含)和 5(不含)之间。

I'm not sure about machine dependence - I've never seen an implementation that was, but I can't say it's never done.

我不确定机器依赖性 - 我从未见过这样的实现,但我不能说它从未完成过。

回答by dF.

As explained in other answers, there are many choices for a modulo operation with negative values. In general different languages (and different machine architectures) will give a different result.

正如其他答案中所解释的,负值的模运算有很多选择。一般来说,不同的语言(和不同的机器架构)会给出不同的结果。

According to the Python reference manual,

根据Python 参考手册

The modulo operator always yields a result with the same sign as its second operand (or zero); the absolute value of the result is strictly smaller than the absolute value of the second operand.

模运算符总是产生一个与它的第二个操作数(或零)具有相同符号的结果;结果的绝对值严格小于第二个操作数的绝对值。

is the choice taken by Python. Basically modulo is defined so that this always holds:

是 Python 的选择。基本上定义了模数,因此这始终成立:

x == (x/y)*y + (x%y)

so it makes sense that (-2)%5 = -2 - (-2/5)*5 = 3

所以 (-2)%5 = -2 - (-2/5)*5 = 3 是有道理的

回答by Jared Updike

Be careful not to rely on this mod behavior in C/C++ on all OSes and architectures. If I recall correctly, I tried to rely on C/C++ code like

注意不要在所有操作系统和体系结构上依赖 C/C++ 中的这种 mod 行为。如果我没记错的话,我尝试依赖 C/C++ 代码,例如

float x2 = x % n;

to keep x2 in the range from 0 to n-1 but negative numbers crept in when I would compile on one OS, but things would work fine on another OS. This made for an evil time debugging since it only happened half the time!

将 x2 保持在 0 到 n-1 的范围内,但是当我在一个操作系统上编译时会出现负数,但在另一个操作系统上一切正常。这使得调试时间很糟糕,因为它只发生了一半!

回答by Steve314

There seems to be a common confusion between the terms "modulo" and "remainder".

术语“模”和“余数”之间似乎存在常见的混淆。

In math, a remainder should alwaysbe defined consistent with the quotient, so that if a / b == c rem dthen (c * b) + d == a. Depending on how you round your quotient, you get different remainders.

在数学,余应始终被定义为与商一致的,因此,如果a / b == c rem d(c * b) + d == a。根据您对商的舍入方式,您会得到不同的余数。

However, modulo should always give a result 0 <= r < divisor, which is only consistent with round-to-minus-infinity division if you allow negative integers. If division rounds towards zero (which is common), modulo and remainder are only equivalent for non-negative values.

但是,取模应始终给出 result 0 <= r < divisor,如果您允许负整数,则该结果仅与舍入到负无穷大除法一致。如果除法向零舍入(这很常见),则模数和余数仅对非负值等效。

Some languages (notably C and C++) don't define the required rounding/remainder behaviours and %is ambiguous. Many define rounding as towards zero, yet use the term modulo where remainder would be more correct. Python is relatively unusual in that it rounds to negative infinity, so modulo and remainder are equivalent.

某些语言(特别是 C 和 C++)没有定义所需的舍入/余数行为并且%是不明确的。许多人将四舍五入定义为向零,但使用术语模数,其中余数会更正确。Python 比较不寻常,因为它四舍五入到负无穷大,所以模和余数是等价的。

Ada rounds towards zero IIRC, but has both modand remoperators.

Ada 向零 IIRC 舍入,但同时具有modandrem运算符。

The C policy is intended to allow compilers to choose the most efficient implementation for the machine, but IMO is a false optimisation, at least these days. A good compiler will probably be able to use the equivalence for optimisation wherever a negative number cannot occur (and almost certainly if you use unsigned types). On the other hand, where negative numbers can occur, you almost certainly care about the details - for portability reasons you have to use very carefully designed overcomplex algorithms and/or checks to ensure that you get the results you want irrespective of the rounding and remainder behaviour.

C 策略旨在允许编译器为机器选择最有效的实现,但 IMO 是一种错误的优化,至少现在是这样。一个好的编译器可能能够在任何不能出现负数的地方使用等价进行优化(如果你使用无符号类型,几乎可以肯定)。另一方面,在可能出现负数的情况下,您几乎肯定会关心细节 - 出于可移植性的原因,您必须使用非常精心设计的超复杂算法和/或检查,以确保无论舍入和余数如何都能获得您想要的结果行为。

In other words, the gain for this "optimisation" is mostly (if not always) an illusion, whereas there are very real costs in some cases - so it's a false optimisation.

换句话说,这种“优化”的收益主要(如果不总是)是一种错觉,而在某些情况下有非常真实的成本 - 所以这是一种错误的优化。

回答by Ozgur Ozcitak

The result depends on the language. Python returns the sign of the divisor, where for example c# returns the sign of the dividend (ie. -2 % 5 returns -2 in c#).

结果取决于语言。Python 返回除数的符号,例如 c# 返回被除数的符号(即 -2 % 5 在 c# 中返回 -2)。

回答by Ozgur Ozcitak

One explanation might be that negative numbers are stored using 2's complement. When the python interpreter tries to do the modulo operation it converts to unsigned value. As such instead of doing (-2) % 5 it actually computes 0xFFFF_FFFF_FFFF_FFFD % 5 which is 3.

一种解释可能是使用2 的补码存储负数。当 python 解释器尝试进行模运算时,它会转换为无符号值。因此,它实际上计算的是 0xFFFF_FFFF_FFFF_FFFD % 5 而不是 (-2) % 5,即 3。