Операция modulo на отрицательных числах в Python

Я нашел странное поведение в Python относительно отрицательных чисел:

>>> a = -5 >>> a % 4 3 

Может ли кто-нибудь объяснить, что происходит?

В отличие от C или C ++, оператор modulo ( % ) Python всегда возвращает число, имеющее тот же знак, что и знаменатель (делитель). Ваше выражение дает 3, потому что

(-5)% 4 = (-2 × 4 + 3)% 4 = 3.

Он выбирается по поведению C, потому что неотрицательный результат часто более полезен. Примером является вычисление недельных дней. Если сегодня вторник (день № 2), каков день недели N дней раньше? В Python мы можем вычислить

 return (2 - N) % 7 

но в C, если N ≥ 3, мы получаем отрицательное число, которое является недопустимым числом, и нам нужно вручную исправить его, добавив 7:

 int result = (2 - N) % 7; return result < 0 ? result + 7 : result; 

(См. http://en.wikipedia.org/wiki/Modulo_operator, как определяется признак результата для разных языков.)

Вот объяснение от Guido van Rossum:

http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html

По существу, это так, что a / b = q с остатком r сохраняет отношения b * q + r = a и 0 <= r

Существует не один лучший способ обработки целых делений и модов с отрицательными числами. Было бы хорошо, если бы a/b была одинаковой величины и противоположного знака (-a)/b . Было бы неплохо, если a % b действительно был модулем b. Поскольку мы действительно хотим, a == (a/b)*b + a%b , первые два несовместимы.

Какой из них держать – это сложный вопрос, и есть аргументы для обеих сторон. C и C ++ округляются до нуля (так что a/b == -((-a)/b) ), и, по-видимому, Python этого не делает.

Как указано, Python modulo делает обоснованное исключение для конвенций других языков.

Это дает отрицательные числа в виде бесшовного поведения, особенно при использовании в сочетании с оператором integer-divide, так как % modulo часто (как в математике divmod ):

 for n in range(-8,8): print n, n//4, n%4 

Производит:

  -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 % всегда выводит ноль или положительный, когда делитель положителен
  • Python // всегда округляется до отрицательной бесконечности

Modulo, classы эквивалентности для 4:

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

Вот ссылка на поведение modulo с отрицательными числами . (Да, я googled это)

Я также думал, что это странное поведение Python. Оказывается, я плохо разбирался в делении (на бумаге); Я указывал значение 0 для частного и значение -5 для остатка. Ужасно … Я забыл геометрическое представление чисел целых чисел. Напомним, что geometry целых чисел, заданная числовой строкой, можно получить правильные значения для частного и остального и проверить, что поведение Python в порядке. (Хотя я предполагаю, что вы уже давно решили свою проблему).

Давайте будем гением компьютера.