The modulo operation on negative numbers in Python
Solution 1
Unlike C or C++, Python's modulo operator (%
) always return a number having the same sign as the denominator (divisor). Your expression yields 3 because
(-5) / 4 = -1.25 --> floor(-1.25) = -2
(-5) % 4 = (-2 × 4 + 3) % 4 = 3.
It is chosen over the C behavior because a nonnegative result is often more useful. An example is to compute week days. If today is Tuesday (day #2), what is the week day N days before? In Python we can compute with
return (2 - N) % 7
but in C, if N ≥ 3, we get a negative number which is an invalid number, and we need to manually fix it up by adding 7:
int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;
(See http://en.wikipedia.org/wiki/Modulo_operator for how the sign of result is determined for different languages.)
Solution 2
Here's an explanation from Guido van Rossum:
http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
Essentially, it's so that a/b = q with remainder r preserves the relationships b*q + r = a and 0 <= r < b.
Solution 3
In python, modulo operator works like this.
>>> mod = n - math.floor(n/base) * base
so the result is (for your case):
mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3
whereas other languages such as C, JAVA, JavaScript use truncation instead of floor.
>>> mod = n - int(n/base) * base
which results in:
mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1
If you need more information about rounding in python, read this.
Solution 4
As pointed out, Python modulo makes a well-reasoned exception to the conventions of other languages.
This gives negative numbers a seamless behavior, especially when used in combination with the //
integer-divide operator, as %
modulo often is (as in math.divmod):
for n in range(-8,8):
print n, n//4, n%4
Produces:
-8 -2 0
-7 -2 1
-6 -2 2
-5 -2 3
-4 -1 0
-3 -1 1
-2 -1 2
-1 -1 3
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3
- Python
%
always outputs zero or positive* - Python
//
always rounds toward negative infinity
* ... as long as the right operand is positive. On the other hand 11 % -10 == -9
Solution 5
There is no one best way to handle integer division and mods with negative numbers. It would be nice if a/b
was the same magnitude and opposite sign of (-a)/b
. It would be nice if a % b
was indeed a modulo b. Since we really want a == (a/b)*b + a%b
, the first two are incompatible.
Which one to keep is a difficult question, and there are arguments for both sides. C and C++ round integer division towards zero (so a/b == -((-a)/b)
), and apparently Python doesn't.
facha
Updated on November 14, 2021Comments
-
facha over 2 years
I've found some strange behaviour in Python regarding negative numbers:
>>> -5 % 4 3
Could anyone explain what's going on?
-
wheaties over 13 yearslooks right to me
-
NullUserException over 13 years
..., -9, -5, -1, 3, 7, ...
-
alexia almost 10 yearspossible duplicate of C,Python - different behaviour of the modulo (%) operation
-
0x2b3bfa0 over 7 yearsYou can use
math.fmod
to get the same behavior as in C or Java.
-
-
wheaties over 13 years@NullUserException - yup, it was. fixed. Thanks.
-
Evgeni Sergeev about 10 yearsLanguages like C++ and Java also preserve the first relationship, but they ceil for negative
a
, positiveb
, whereas Python floors. It's always true thatabs(r) < b
, and they ceil iffr <= 0
. -
Lamis over 7 yearsThanks your example made me understand it :)
-
zezollo over 6 yearsSurprisingly, Python's modulo operator (%) does not always return a number having the same sign as the denominator (divisor). See stackoverflow.com/questions/48347515/…
-
user76284 over 4 years"It would be nice if a/b was the same magnitude and opposite sign of (-a)/b." Why would that be nice? When is that a desired behaviour?
-
Demis almost 4 yearsBecause it would then act the same way as regular division and multiplication, and is thus intuitively easy to work with. That may not makes sense mathematically though.
-
Astariul about 3 yearsLink seems to be dead
-
wheaties about 3 years@Astariul big problem with the internet. If you have an alternative suggestion, I'm all for it. That said, it's an 11yr old post!
-
Alex over 2 yearsThanks for visualization, it really helped. Wanted to add on 'But in Python, we have a forward direction for all modulo operations.'. How about 7 % -3, or 7 % -3? Isn't that backward direction?
-
Deekshant over 2 years@Alex yes you are right, I meant "for all positive modulo operations".
-
KansaiRobot over 2 yearsI don't understand your explanation
-
Paul almost 2 yearsThanks for the graphs, clear! Why does -5%4 give 3? Visualizing it on a number line didn't make it very clear for me.
-
Deekshant almost 2 years@elyakshaver Think of it this way, in python, you always have to go right (in case of doing modulo with +ve numbers) to reach the number you want to go to. 4*-1 = -4, you can never reach -5 from -4 by going right, so you jump back. 4*-2 = -8, now you can reach -5 by hoping 3 steps to the right, hence -5%4=3.
-
Abercrombie almost 2 yearsBest explanation so far