Почему оператор% называется оператором "модуль" вместо оператора "остатка"?
Сегодня на работе у меня была интересная дискуссия с одним из моих сотрудников. Он был удивлен, когда с ним случилось следующее:
assert(-1 % 10 == -1) //Expecting 9
Итак, когда он пришел, чтобы спросить меня об этом, я сказал ему: "Ну, это имеет смысл. Когда вы разделите -1 на 10, вы получите 0 с остатком -1. Однако его аргумент заключался в том, что оператор модуля должен Верно для" всегда положительной" модели. Я сделал небольшое исследование и обнаружил, что модуль, который он имел в виду, выглядит следующим образом:
Пусть q - целое число a и n. Пусть г - остаток. Тогда:
a = n * q + r
Однако определение, которое я использовал, является версией модуля Knuth, которая:
Пусть q - пол деления на n. Пусть г - остаток. Тогда:
r = a - n * q
Итак, мой вопрос в том, почему он оказался в стандарте FORTRAN (а затем и в C-стандарте), чтобы оператор модуля был усечен в направлении 0? Мне кажется неправильным, чтобы назвать его "модулем", а не "остатком" (в математике ответ действительно должен быть 9). Связано ли это с тем, как аппаратное обеспечение выполняет разделение?
Для справки:
TL;DR; Является ли аппаратное обеспечение причиной того, что оператор модуля усекает в направлении 0?
Ответы
Ответ 1
Мне кажется неправильным назвать его "модулем", а не "остатком" (в математике ответ действительно должен быть 9).
C называет его оператором% и называет его результат оставшимся. С++ копирует это из C. Ни один из языков не называет это оператором модуля. Это также объясняет, почему остаток отрицательный: поскольку оператор/усекает в направлении 0, а (a / b) * b + (a % b)
должен равняться a
.
Изменить: Дэвид Родригес справедливо указывает, что С++ определяет класс шаблона std::modulus
, который вызывает operator%
. На мой взгляд, этот класс плохо назван. Копаясь немного, он унаследован от STL, где он уже был назван так, как сейчас. Загрузка для STL говорит: "STL был разработан на SGI MIPSproTM С++ 7.0, 7.1, 7.2 и 7.2.1.", И, насколько я могу судить, без фактического наличия компилятора и аппаратного обеспечения, MIPSpro передает разделение на CPU и Аппаратное обеспечение MIPS обрезается до 0, что означает, что std::modulus
всегда было неправильно.
Ответ 2
%
- оператор остатка в C и С++.
В стандарте С++ он называется оператором %
, и он дает остаток от деления. В стандарте C он называется оператором %
, а с C99 он фактически является оператором остатка. Операторы по модулю и остатку различаются относительно отрицательных значений.
Оператор %
определен в C и С++ с a == (a / b * b) + a % b
.
Усечение целочисленного деления на 0 в C выполняется с C99. В C89 была определена реализация (и %
может быть модульным оператором в C89). С++ также выполняет усечение к нулю для целочисленного деления.
Когда усечение выполняется к нулю, %
- оператор остатка, а знак результата - знак дивиденда. Когда усечение выполняется в сторону минус бесконечности, %
является модульным оператором, а знак результата является знаком делителя.
В связи с тем, что C изменило реализацию, определенную поведением целочисленного деления относительно усечения, Дуг Гвин из C комитета сказал:
C99 наложила требование, совместимое с Fortran, в попытке привлечь больше программистов Fortran и помочь преобразовать код Fortran в C.
C99 Обоснование говорит об усечении в нулевое целочисленное деление:
В Fortran, однако, результат всегда будет усекать до нуля, а служебные данные, по-видимому, приемлемы для сообщества с числовым программным обеспечением. Поэтому C99 теперь требует аналогичного поведения, что должно облегчить перенос кода из Fortran на C.
В gcc
поведение реализации на C89 всегда было усечением к нулю.
Итак, %
- это оператор останова в C99, С++, а также в Java, но не является оператором остатка на всех языках программирования. В Ruby и Python %
на самом деле является модульным оператором (целочисленное деление делается на минус бесконечность на этих языках). Haskhell и Scheme имеют два отдельных оператора: mod
и rem
для Haskell и modulo
и remainder
для Схемы.
Ответ 3
Я боюсь, что проблема возникает из-за непонимания математики. Конгруэнция по модулю n является отношением эквивалентности, поэтому она определяет только классы эквивалентности. Следовательно, он не правильно сказал, что "в математике ответ действительно должен быть 9", потому что это может быть также 19, 29 и т.д. И, конечно, это может быть -1 или -11. Существуют бесконечные элементы класса чисел n, которые являются n ≡ -1 mod (10).
http://en.wikipedia.org/wiki/Modular_arithmetic
http://en.wikipedia.org/wiki/Congruence_relation
Итак, правильным может быть вопрос: какой элемент класса чисел, который является ≡ -1 mod (10), будет результатом -1% 10 в С++? И ответ таков: остаток от деления -1 на 10. Нет тайны.
PS Ваше определение модуля и Knuth равно ehm, равно...:)