The modulo operation on negative numbers in Python

前端 未结 8 1870
无人共我
无人共我 2020-11-22 14:26

I\'ve found some strange behaviour in Python regarding negative numbers:

>>> -5 % 4
3

Could anyone explain what\'s going on?

相关标签:
8条回答
  • 2020-11-22 14:39

    Modulo, equivalence classes for 4:

    • 0: 0, 4, 8, 12... and -4, -8, -12...
    • 1: 1, 5, 9, 13... and -3, -7, -11...
    • 2: 2, 6, 10... and -2, -6, -10...
    • 3: 3, 7, 11... and -1, -5, -9...

    Here's a link to modulo's behavior with negative numbers. (Yes, I googled it)

    0 讨论(0)
  • 2020-11-22 14:42

    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.)

    0 讨论(0)
  • 2020-11-22 14:44

    It's also worth to mention that also the division in python is different from C: Consider

    >>> x = -10
    >>> y = 37
    

    in C you expect the result

    0
    

    what is x/y in python?

    >>> print x/y
    -1
    

    and % is modulo - not the remainder! While x%y in C yields

    -10
    

    python yields.

    >>> print x%y
    27
    

    You can get both as in C

    The division:

    >>> from math import trunc
    >>> d = trunc(float(x)/y)
    >>> print d
    0
    

    And the remainder (using the division from above):

    >>> r = x - d*y
    >>> print r
    -10
    

    This calculation is maybe not the fastest but it's working for any sign combinations of x and y to achieve the same results as in C plus it avoids conditional statements.

    0 讨论(0)
  • 2020-11-22 14:45

    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

    0 讨论(0)
  • 2020-11-22 14:50

    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.

    0 讨论(0)
  • 2020-11-22 14:58

    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.

    0 讨论(0)
提交回复
热议问题