Работа модуля с отрицательными значениями - странное дело?

Подскажите пожалуйста сколько стоит (-2) % 5? Согласно моему интерпретатору Python - 3, но есть ли у вас мудрое объяснение этому?

Я читал, что на некоторых языках результат может зависеть от машины, но я не уверен.

Вы можете использовать math.fmod, чтобы добиться того же поведения, что и в C или Java.

0x2b3bfa0 28.01.2017 19:42
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
18
1
11 336
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Ваш интерпретатор Python правильный. Один (глупый) способ вычисления модуля - вычесть или добавить модуль, пока результирующее значение не будет между 0 и (модуль - 1).

например.: 13 по модулю 5 = (13-5) по модулю 5 = (13-10) по модулю 5 = 3

или в вашем случае: −2 mod 5 = (−2 + 5) mod 5 = 3

Это зависит от того, как определяется целочисленное деление. Если при делении округляется до 0, то остаток должен иметь тот же знак, что и частное, так что b * (a/b) + a%b == a. Если деление округляется до отрицательной бесконечности (как в Python), остаток всегда должен быть положительным.

augurar 21.08.2014 10:39

Ну, -2, разделенное на 5, даст 0 с остатком 3. Я не верю, что это должно сильно зависеть от платформы, но я видел более странные вещи.

Вы наверняка имеете в виду: «-2, разделенное на 5, будет -1, а остаток - 3», верно? Во всяком случае, это то, что делает Python.

tzot 12.07.2010 02:11

В некоторых системах -2, деленное на 5, дает 0 с остатком -2. В других случаях это -1, а остаток - 3. Просто дело вкуса, "правильного" ответа не существует.

augurar 21.08.2014 10:33

Это действительно 3. В модульная арифметика модуль - это просто остаток от деления, а остаток от -2, деленный на 5, равен 3.

В выражении c = a%bb означает модуль, а не c.

augurar 21.08.2014 10:31

Результат операции модуля на негативе, по-видимому, зависит от языка программирования, и вот листинг http://en.wikipedia.org/wiki/Modulo_operation

Ну, 0% 5 должно быть 0, верно?

-1% 5 должно быть 4, потому что это следующая допустимая цифра, идущая в обратном направлении (то есть не может быть 5, так как это вне диапазона).

И, следуя этой логике, -2 должно быть 3.

Самый простой способ подумать о том, как это будет работать, - это продолжать добавлять или вычитать 5, пока число не окажется между 0 (включительно) и 5 ​​(исключая).

Я не уверен в зависимости от машины - я никогда не видел такой реализации, но не могу сказать, что она никогда не была реализована.

Ответ принят как подходящий

Кстати: большинство языков программирования не согласятся с Python и выдадут результат -2. В зависимости от интерпретации модуля это верно. Однако наиболее согласованное математическое определение утверждает, что модуль а и б является (строго положительным) остатком р деления а / б. Точнее, 0 <= р <б по определению.

Результат зависит от языка. Python возвращает знак делителя, где, например, C# возвращает знак делимого (т.е. -2% 5 возвращает -2 в C#).

Одно из объяснений может заключаться в том, что отрицательные числа хранятся с использованием 2 дополнения. Когда интерпретатор python пытается выполнить операцию по модулю, он преобразуется в значение без знака. Таким образом, вместо выполнения (-2)% 5 он фактически вычисляет 0xFFFF_FFFF_FFFF_FFFD% 5, что равно 3.

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

Согласно Справочное руководство по Python,

The modulo operator always yields a result with the same sign as its second operand (or zero); the absolute value of the result is strictly smaller than the absolute value of the second operand.

это выбор, сделанный Python. В основном по модулю определяется так, что это всегда выполняется:

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

поэтому имеет смысл, что (-2)% 5 = -2 - (-2/5) * 5 = 3

Будьте осторожны, чтобы не полагаться на это поведение мода в C / C++ во всех операционных системах и архитектурах. Если я правильно помню, я пытался полагаться на код C / C++, например

float x2 = x % n;

чтобы сохранить x2 в диапазоне от 0 до n-1, но когда я компилировал на одной ОС, вкрались отрицательные числа, но на другой ОС все будет работать нормально. Это было ужасно для отладки, так как это происходило только в половине случаев!

Как говорится в документации в Двоичные арифметические операции, Python гарантирует, что:

The integer division and modulo operators are connected by the following identity: x == (x/y)*y + (x%y). Integer division and modulo are also connected with the built-in function divmod(): divmod(x, y) == (x/y, x%y).

И действительно,

>>> divmod(-2, 5)
(-1, 3).

Другой способ визуализировать единообразие этого метода - вычислить divmod для небольшой последовательности чисел:

>>> for number in xrange(-10, 10):
...     print divmod(number, 5)
...
(-2, 0)
(-2, 1)
(-2, 2)
(-2, 3)
(-2, 4)
(-1, 0)
(-1, 1)
(-1, 2)
(-1, 3)
(-1, 4)
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(1, 4)

Кажется, существует обычная путаница между терминами «по модулю» и «остаток».

В математике остаток должен быть определен всегда в соответствии с частным, так что если a / b == c rem d, то (c * b) + d == a. В зависимости от того, как округлить частное, вы получите разные остатки.

Однако по модулю всегда должен возвращаться результат 0 <= r < divisor, который согласуется с округлением до минус бесконечности, только если вы разрешаете отрицательные целые числа. Если деление округляется до нуля (что является обычным явлением), модуль и остаток эквивалентны только для неотрицательных значений.

Некоторые языки (особенно C и C++) не определяют требуемого поведения округления / остатка, а % неоднозначен. Многие определяют округление как направление к нулю, но используют термин по модулю, когда остаток был бы более правильным. Python относительно необычен тем, что округляет до отрицательной бесконечности, поэтому по модулю и остатку эквивалентны.

В Ada округляется к нулю IIRC, но есть операторы mod и rem.

Политика C предназначена для того, чтобы позволить компиляторам выбирать наиболее эффективную реализацию для машины, но IMO - это ложная оптимизация, по крайней мере, в наши дни. Хороший компилятор, вероятно, сможет использовать эквивалентность для оптимизации там, где отрицательное число не может появиться (и почти наверняка, если вы используете беззнаковые типы). С другой стороны, там, где могут встречаться отрицательные числа, вы почти наверняка заботитесь о деталях - по причинам переносимости вы должны использовать очень тщательно разработанные сверхкомплексные алгоритмы и / или проверки, чтобы гарантировать получение желаемых результатов независимо от округления и остатка. поведение.

Другими словами, выгода от этой «оптимизации» в основном (если не всегда) является иллюзией, тогда как в некоторых случаях есть очень реальные затраты - так что это ложная оптимизация.

Другие вопросы по теме