Почему модуль отличается в разных языках программирования? - PullRequest
21 голосов
/ 16 января 2009

Perl

print 2 % -18;

->

-16

Tcl

puts [expr {2 % -18}]

->

-16

но VBScript

wscript.echo 2 mod -18

->

2

Почему разница?

Ответы [ 4 ]

30 голосов
/ 16 января 2009

Ответ из Википедии довольно полезен здесь.

Краткое резюме: любое целое число можно определить как

a = qn + r

, где все эти буквы являются целыми числами, а

0 <= | r | <| n |. </p>

Почти для каждого языка программирования требуется, чтобы (a / n) * n + (a% n) = a. Таким образом, определение модуля почти всегда будет зависеть от определения целочисленного деления. Есть два варианта целочисленного деления на отрицательные числа 2 / -18 = 0 или 2 / -18 = -1. В зависимости от того, какой из них верен для вашего языка, обычно меняется оператор%.

Это потому, что 2 = (-1) * -18 + (-16) и 2 = 0 * -18 + 2.

Для Perl ситуация сложная. Страница справочника гласит: «Обратите внимание, что когда целочисленное использование находится в области видимости,«% »дает вам прямой доступ к оператору модуля, как это реализовано вашим компилятором C. Этот оператор не так хорошо определен для отрицательных операндов, но он будет выполняться быстрее. "Таким образом, он может выбрать любую опцию для Perl (например, C), если целое использование находится в области видимости. Если целочисленное использование не входит в область действия, руководство говорит: «Если $ b отрицательно, то $ a% $ b равно $ a минус наименьшее кратное значение $ b, которое не меньше, чем $ a (т. Е. Результат будет меньше или равно нулю). "

9 голосов
/ 16 января 2009

Википедия "Операция по модулю" объясняет это довольно хорошо. Я не буду пытаться делать что-то лучше здесь, потому что я, вероятно, сделаю небольшую, но важную ошибку.

Суть в том, что вы можете определять «остаток» или «модуль» по-разному, и разные языки выбрали разные варианты реализации.

4 голосов
/ 16 января 2009

После деления числа и делителя, один из которых является отрицательным, у вас есть по крайней мере два способа разделить их на частное и остаток, так что частное * делитель + остаток = число: вы можете либо округлить частное в сторону отрицательная бесконечность или к нулю.

Многие языки просто выбирают один.

Не могу не отметить, что Common Lisp предлагает оба варианта.

2 голосов
/ 13 марта 2009

Python, конечно, явно информирует вас

>>> divmod(2,-18)
(-1, -16)
...