Почему оператор% называется оператором «модуля» вместо оператора «остатка»? - PullRequest
22 голосов
/ 15 февраля 2012

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

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

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

Пусть q - целое число от a и n. Пусть г будет остаток. Тогда:

a = n * q + r

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

Пусть q - пол деленного на n. Пусть г будет остаток. Тогда:

r = a - n * q

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

Для справки:

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

Ответы [ 3 ]

16 голосов
/ 15 февраля 2012

Мне кажется неправильным называть это «модулем», а не «остатком» (в математике ответ действительно должен быть 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 всегда было неправильно названо.

5 голосов
/ 15 февраля 2012

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

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

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

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

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

По причинам, по которым C изменил поведение, определяемое реализацией целочисленного деления в отношении усечения, Дуг Гвин из комитета C сказал:

C99 наложил совместимое с Фортраном требование в попытке привлечь больше фортрановских программистов и помочь в преобразовании кода Фортрана в C.

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

В Фортране, однако, результат всегда будет обрезаться до нуля, и накладные расходы кажутся приемлемыми для сообщества числового программирования. Поэтому C99 теперь требует аналогичного поведения, что должно облегчить перенос кода с Fortran на C.

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

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

1 голос
/ 15 февраля 2012

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

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

...