8
votes

Been looking through other answers and I still don't understand the modulo for negative numbers in python

For example the answer by df

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

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

Doesn't this (-2 - (-2/5)*5) =0 or am I just crazy? Modulus operation with negatives values - weird thing?

Same with this negative numbers modulo in python Where did he get -2 from?

Lastly if the sign is dependent on the dividend why don't negative dividends have the same output as their positive counterparts?

For instance the output of

print([8%5,-8%5,4%5,-4%5])

is

[3, 2, 4, 1]
6
You can use math.fmod to get the same behavior as in C or Java.0x2b3bfa0

6 Answers

11
votes

In Python, modulo is calculated according to two rules:

  • (a // b) * b + (a % b) == a, and
  • a % b has the same sign as b.

Combine this with the fact that integer division rounds down (towards −∞), and the resulting behavior is explained.

If you do -8 // 5, you get -1.6 rounded down, which is -2. Multiply that by 5 and you get -10; 2 is the number that you'd have to add to that to get -8. Therefore, -8 % 5 is 2.

7
votes

In Python, a // b is defined as floor(a/b), as opposed to most other languages where integer division is defined as trunc(a/b). There is a corresponding difference in the interpretation of a % b = a - (a // b) * b.

The reason for this is that Python's definition of the % operator (and divmod) is generally more useful than that of other languages. For example:

def time_of_day(seconds_since_epoch):
    minutes, seconds = divmod(seconds_since_epoch, 60)
    hours, minutes = divmod(minutes, 60)
    days, hours = divmod(hours, 24)
    return '%02d:%02d:%02d' % (hours, minutes, seconds)

With this function, time_of_day(12345) returns '03:25:45', as you would expect.

But what time is it 12345 seconds before the epoch? With Python's definition of divmod, time_of_day(-12345) correctly returns '20:34:15'.

What if we redefine divmod to use the C definition of / and %?

def divmod(a, b):
    q = int(a / b)   # I'm using 3.x
    r = a - b * q
    return (q, r)

Now, time_of_day(-12345) returns '-3:-25:-45', which isn't a valid time of day. If the standard Python divmod function were implemented this way, you'd have to write special-case code to handle negative inputs. But with floor-style division, like my first example, it Just Works.

3
votes

The rationale behind this is really the mathematical definition of least residue. Python respects this definition, whereas in most other programming language the modulus operator is really more like a 'reaminder after division' operator. To compute the least residue of -5 % 11, simply add 11 to -5 until you obtain a positive integer in the range [0,10], and the result is 6.

0
votes

When you divide ints (-2/5)*5 does not evaluate to -2, as it would in the algebra you're used to. Try breaking it down into two steps, first evaluating the part in the parentheses.

  1. (-2/5) * 5 = (-1) * 5
  2. (-1) * 5 = -5

The reason for step 1 is that you're doing int division, which in python 2.x returns the equivalent of the float division result rounded down to the nearest integer.

In python 3 and higher, 2/5 will return a float, see PEP 238.

0
votes

Check out this BetterExplained article and look @ David's comment (No. 6) to get what the others are talking about.

Since we're working w/ integers, we do int division which, in Python, floors the answer as opposed to C. For more on this read Guido's article.

As for your question:

>>> 8 % 5  #B'coz (5*1) + *3* = 8
3
>>> -8 % 5 #B'coz (5*-2) + *2* = -8
2

Hope that helped. It confused me in the beginning too (it still does)! :)

0
votes

Say -a % b needs to be computed. for ex. r= 11 % 10 find the next number after 11 that is perfectly divisible by 10 i.e on dividing that next number after 11 gives the remainder 0.

In the above case its 20 which on dividing by 10 gives 0. Hence, 20-11 = 9 is the number that needs to be added to 11.

The concept if 60 marbles needs to be equally divided among 8 people, actually what you get after dividing 60/8 is 7.5 since you can'nt halve the marbles, the next value after 60 that is perfectly divisible by 8 is 64. Hence 4 more marbles needs to be added to the lot so that everybody share the same joy of marbles.

This is how Python does it when negatives numbers are divided using modulus operator.