The modulo operation on negative numbers in Python

100,956

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.

Share:
100,956
facha
Author by

facha

Updated on November 14, 2021

Comments

  • facha
    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
      wheaties over 13 years
      looks right to me
    • NullUserException
      NullUserException over 13 years
      ..., -9, -5, -1, 3, 7, ...
    • alexia
      alexia almost 10 years
    • 0x2b3bfa0
      0x2b3bfa0 over 7 years
      You can use math.fmod to get the same behavior as in C or Java.
  • wheaties
    wheaties over 13 years
    @NullUserException - yup, it was. fixed. Thanks.
  • Evgeni Sergeev
    Evgeni Sergeev about 10 years
    Languages like C++ and Java also preserve the first relationship, but they ceil for negative a, positive b, whereas Python floors. It's always true that abs(r) < b, and they ceil iff r <= 0.
  • Lamis
    Lamis over 7 years
    Thanks your example made me understand it :)
  • zezollo
    zezollo over 6 years
    Surprisingly, Python's modulo operator (%) does not always return a number having the same sign as the denominator (divisor). See stackoverflow.com/questions/48347515/…
  • user76284
    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
    Demis almost 4 years
    Because 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
    Astariul about 3 years
    Link seems to be dead
  • wheaties
    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
    Alex over 2 years
    Thanks 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
    Deekshant over 2 years
    @Alex yes you are right, I meant "for all positive modulo operations".
  • KansaiRobot
    KansaiRobot over 2 years
    I don't understand your explanation
  • Paul
    Paul almost 2 years
    Thanks 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
    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
    Abercrombie almost 2 years
    Best explanation so far