Есть ли причина, по которой некоторые языки допускают отрицательный модуль? - PullRequest
9 голосов
/ 30 ноября 2011

Мне любопытно узнать об этих языках (Java, C ...), которые игнорируют математическое определение операции модуля.

Какой смысл возвращать отрицательные значения в операции модуля (которая по определению должнавсегда возвращайте положительное число)?

Ответы [ 6 ]

7 голосов
/ 30 ноября 2011

По крайней мере, в Java это не оператор модуля - это оператор остатка .

Я полагаю, что причина его выбора заключается в том, чтобы заставить эти отношения работать (из JLS):

Операция остатка для операндов, которые являются целыми числами после двоичного преобразования чисел (§5.6.2), приводит к значению результата, так что (a / b) * b + (a% b) равно a. Эта идентичность сохраняется даже в частном случае, когда дивиденд является отрицательным целым числом наибольшей возможной величины для его типа, а делитель равен -1 (остаток равен 0). Из этого правила следует, что результат операции остатка может быть отрицательным, только если дивиденд является отрицательным, и может быть положительным, только если дивиденд является положительным; более того, величина результата всегда меньше величины делителя.

Это соотношение равенства кажется разумным для использования в качестве части определения. Если вы берете усечение деления в сторону нуля как данность, это оставляет вас с отрицательным остатком.

6 голосов
/ 30 ноября 2011

Из Википедия (мой акцент):

Учитывая два положительных числа, а (дивиденд) и п (делитель), а модуль n (сокращенно как mod n) можно рассматривать как остаток, на разделение. Например, выражение «5 мод 4» будет оцените как 1, потому что 5, разделенное на 4, оставляет остаток от 1, а "9 Мод 3 "будет оцениваться до 0, потому что деление 9 на 3 оставляет остаток от 0; нечего вычитать из 9 после умножения 3 раза 3. (Обратите внимание, что деление калькулятором не показать вам результат, упомянутый здесь этой операцией, частное будет выражаться в виде десятичной дроби.) Когда a или n отрицательны, это наивное определение ломается, и языки программирования отличаются как эти значения определены. Хотя обычно выполняется с и n оба являются целыми числами, многие вычислительные системы допускают другие типы числовые операнды. Диапазон чисел для целого числа по модулю n равен 0 к n - 1. (n mod 1 всегда равно 0; n mod 0 не определено, возможно что приводит к ошибке "Деление на ноль" в компьютерном программировании языки) См. модульную арифметику для старых и связанных с ними соглашений применяется в теории чисел.

4 голосов
/ 30 ноября 2011

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

Скорее, отрицательные остатки являются побочным эффектомспособа целочисленного деления определяется.

A rem B := A - (A div B) * B

Если A div B определено как trunc(A/B), вы получите оператор C's %.Если A div B определено как floor(A/B), вы получите оператор % Python.Возможны и другие определения.

Итак, реальный вопрос заключается в следующем:

Почему в C ++, Java, C # и т. Д. Используется усеченное целочисленное деление?

Потому что такC делает это.

Почему C использует усеченное деление?

Изначально C не определял, как / должен обрабатывать отрицательные числа.Он оставил это на усмотрение аппаратного обеспечения.

На практике в каждой существенной реализации C использовалось усеченное деление, поэтому в 1999 г. эта семантика была формально включена в стандарт C.

Почему аппаратное обеспечение используетсяусеченное деление?

Потому что это проще (= дешевле) реализовать с точки зрения беззнакового деления.Вы просто вычисляете abs(A) div abs(B) и переворачиваете знак, если (A < 0) xor (B < 0).

Поэтажное деление имеет дополнительный шаг вычитания 1 из частного, если остаток ненулевой.

3 голосов
/ 30 ноября 2011

Большинство из них не определены для возврата модуля. То, что они определены для возврата, является остатком, для которого положительные и отрицательные значения одинаково разумны.

В C или C ++ вполне разумно сказать, что он должен производить то, что производит базовое оборудование. Это оправдание / причина не работает почти так же хорошо для Java.

Также обратите внимание, что в C89 / 90 и C ++ 98/03 остаток может быть либо положительным, либо отрицательным, если результаты от остатка и деления работают вместе ((a/b)*b+a%b == a). В C99 и C ++ 11 правила были ужесточены, поэтому деление должно обрезаться до нуля, а если есть остаток, он должен быть отрицательным.

1 голос
/ 30 ноября 2011

Ни в одном из стандартов C или Java % не упоминается как оператор модуля - скорее, он возвращает остаток .

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

1 голос
/ 30 ноября 2011

Прагматичной причиной для возврата отрицательного значения для модуля является то, что аппаратная инструкция, реализующая модуль, делает это.

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

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