2012-02-14 3 views
20

Сегодня на работе у меня была интересная дискуссия с одним из моих коллег. Он был удивлен, когда он имел следующие с ним случиться:Почему оператор% называется оператором «модуль» вместо оператора «остатка»?

assert(-1 % 10 == -1) //Expecting 9 

Так что, когда он пришел, чтобы спросить меня об этом, я сказал ему: «хорошо, что имеет смысл, если вы разделите -1 на 10, вы получите 0. с остатком -1. Однако его аргумент заключался в том, что оператор модуля должен придерживаться «всегда положительной» модели. Я провел небольшое исследование и обнаружил, что модуль, который он имел в виду, выглядит следующим образом:

Пусть q - целое число a и n. Пусть r - остаток. Затем:

a = n * q + r

Определение я использовал, однако, по-видимому, версия Кнут модуля, который является:

Пусть q- пол разделенный на п. Пусть г - остаток. Тогда:

г = а - п * д

Итак, мой вопрос, почему он оказался в стандарте FORTRAN (и впоследствии C-стандарт), чтобы оператор модуля усечение в сторону 0? Мне кажется неправильным, чтобы назвать его «модулем», а не «остатком» (в математике ответ действительно должен быть 9). Связано ли это с тем, как аппаратное обеспечение выполняет разделение?

Для справки:

TLDR; Является ли аппаратное обеспечение причиной того, что оператор модуля усекает в направлении 0?

+3

Вы понимаете, что этот вопрос и ссылки полны причин, чтобы избежать по модулю с отрицательными операндами? –

+4

Избегайте, это не вопрос. –

+0

Действительно ли это называется «модуль» или «мода»? Сколько слогов имеет «мода»? Как насчет «остатка»? – supercat

ответ

15

Похож некорректный мне назвать его «модулем», а не «остаток» (В математике, ответ действительно должен быть 9).

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

Редактировать: Дэвид Родригес справедливо указывает на то, что C++ делает определить шаблон класса std::modulus, который вызывает operator%. На мой взгляд, этот класс плохо назван. Копаясь немного, он унаследован от STL, где он уже был назван так, как сейчас. Загрузка для STL говорит: «STL был разработан на SGI MIPSproTM C++ 7.0, 7.1, 7.2 и 7.2.1.», и, насколько я могу судить, без фактического наличия компилятора и аппаратного обеспечения, MIPSpro передает разделение на процессор, а аппаратное обеспечение MIPS обрезается до 0, что означает, что std::modulus всегда было неправильно.

+2

+1 Я только что проверил стандарт C++: * двоичный оператор% дает остаток от деления первого выражения на второе *, поэтому +1 для самого оператора. Теперь еще одна проблема - это имя функтора в 'functional', которое использует' operator% ', который называется * модулем *, поэтому по крайней мере часть вопроса остается открытой ... –

+0

@ DavidRodríguez-dribeas Ницца найти, я не могу ответить по истории за этим и почему он назван так, как есть. – hvd

+1

Я думаю, что источник замешательства, по крайней мере для меня, заключается в том, что, если вы используете, например, 'fmod', вы не получите истинного модуля, как это подразумевалось в названии. Кажется, что два слова используются взаимозаменяемо. Но вы правы, истинный стандарт C++ говорит об остатке. Первоначальным источником, который я использовал, был MSDN, потому что я смотрел специально для VS2003. http://msdn.microsoft.com/en-us/library/ty2ax9z9(v=vs.71).aspx. Похоже, что они неверны. –

4

% - оператор остатка в с и с ++.

В стандарте C++, это называется оператором % и это дает остаток от деления. В C стандарте это называется % оператора и так как C99 это на самом деле остаточный оператор. Операторы по модулю и остатку отличаются относительно отрицательных значений.

Оператор % определен в C и C++ с a == (a/b * b) + a % b.

Усечение целочисленного деления на 0 в C выполняется с C99. В C89 была определена реализация (и % может быть модульным оператором в C89). C++ также выполняет усечение к нулю для целочисленного деления.

При усечении до нуля, % является оператором остатка, а знак результата является признаком дивиденда. Когда усечение делается в сторону минус бесконечности, % является модульным оператором, а знак результата - знаком дивизора.

О причинах, почему C изменили реализации определенного поведения целочисленного деления относительно усечения, Дуги Гвин из C комитета сказали:

C99 ввел Fortran-совместимого требование в попытке привлечь больше Fortran rogrammers и чтобы помочь в преобразовании Fortran кода C.

C99 Обоснование говорит о усечения к нулю целочисленного деления:

Однако в Fortran результат всегда будет усекаться к нулю, а служебные данные, по-видимому, приемлемы для сообщества численного программирования. Таким образом, C99 теперь требует подобного поведения, которая должна облегчить перенос кода от Fortran до C.

В gcc поведение реализации в C89 всегда было усечение к нулю.

Таким образом, % является оператором остатка в C99, C++, а также на Java, но не является оператором остатка на всех языках программирования. В Ruby и Python % фактически является модульным оператором (целочисленное деление делается на минус бесконечность на этих языках). Haskhell и Scheme имеют два отдельных оператора: mod и rem для Haskell и modulo и remainder для Схемы.

+0

Haskhell а? ;) – NateS

1

Я боюсь, что проблема возникает из-за непонимания математики. Конгруэнция по модулю 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 по модулю (10) будет являться результатом -1% 10 в C++ ? И ответ: осталось деления -1 на 10. Нет тайны.

PS Ваше определение модуля и Кнут являются, ЭУ, что эквивалентно ... :)

+0

Эти определения не равны. Подключите -1% 10, и вы поймете, почему. –

+0

Почему? «Пусть q - целое число a и n», то же самое имеет значение «Пусть q - пол деления на n». Остальная часть определения совершенно равна, учитывая, что вы переворачиваете n * q с другой стороны равного ...;) – ascanio

+3

Многие люди ожидали, что операция% вернет уникальный представитель класса эквивалентности. Это не так, потому что он возвращает разные представители для пар целых чисел, принадлежащих к одному классу эквивалентности (x и -x, x! = 0). Ваш аргумент, что -1% 10 может быть -1 или -11, имеет смысл только в том случае, если всегда используется одинаковое смещение от [0, m-1] (например, если -1% 10 = -11, то 9% 10 тоже be -11, а не 9). –