Операция по модулю отрицательных чисел в Python - PullRequest
58 голосов
/ 07 октября 2010

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

>>> -5 % 4
3

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

Ответы [ 7 ]

94 голосов
/ 07 октября 2010

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

(- 5)% 4 = (-2 & times; 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 о том, как определяется знак результата для разных языков.)

25 голосов
/ 07 октября 2010

Вот объяснение Гвидо ван Россума:

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

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

8 голосов
/ 07 октября 2010

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

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

4 голосов
/ 06 марта 2015

Как указывалось, Python по модулю делает аргументированное исключение из соглашений других языков.

Это дает отрицательным числам плавное поведение, особенно при использовании в сочетании с оператором целочисленного деления //, как часто % по модулю (как в математике. 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 // всегда округляется в сторонуотрицательная бесконечность
3 голосов
/ 07 октября 2010

Модуль по классу эквивалентности для 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 ...

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

1 голос
/ 09 ноября 2016

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

0 голосов
/ 22 мая 2019

Стоит также отметить, что деление в python отличается от C: рассмотрим

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

в C, вы ожидаете результат

0

что такое х / у вpython?

>>> print x/y
-1

и% по модулю - не остаток!В то время как x% y в C даёт

-10

python, даётся.

>>> print x%y
27

Вы можете получить оба, как в C

Разделение:

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

И остаток (с использованием деления сверху):

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

Этот расчет, возможно, не самый быстрый, но он работает для любых комбинаций знаков x и y для достижения тех же результатов, что и в C плюсизбегает условных выражений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...