В вычислениях операция деления по модулю возвращает остаток или знаковый остаток от деления после деления одного числа на другое, называемый модулем операции.
Для двух положительных чисел a и n , модуль n (часто сокращенно a mod n ) является остатком от евклидова деления числа a на n , где a — делимое , а n — делитель . [1]
Например, выражение «5 mod 2» даст результат 1, поскольку 5 при делении на 2 даст частное 2 и остаток 1, тогда как выражение «9 mod 3» даст результат 0, поскольку 9 при делении на 3 даст частное 3 и остаток 0.
Хотя обычно выполняется с a и n , оба являющимися целыми числами , многие вычислительные системы теперь допускают другие типы числовых операндов. Диапазон значений для операции целочисленного модуля n составляет от 0 до n − 1 ( mod 1 всегда равен 0; mod 0 не определен, поскольку является делением на ноль ).
Когда хотя бы одно из чисел a или n отрицательно, базовое определение нарушается, и языки программирования различаются в том, как определяются эти значения.
В математике результатом операции по модулю является класс эквивалентности , и любой член класса может быть выбран в качестве представителя ; однако, обычным представителем является наименьший положительный остаток , наименьшее неотрицательное целое число, принадлежащее этому классу (т. е. остаток от евклидова деления ). [2] Однако возможны и другие соглашения. Компьютеры и калькуляторы имеют различные способы хранения и представления чисел; таким образом, их определение операции по модулю зависит от языка программирования или базового оборудования .
Почти во всех вычислительных системах частное q и остаток r от деления a на n удовлетворяют следующим условиям:
( 1 ) |
Это все еще оставляет неоднозначность знака, если остаток не равен нулю: возможны два варианта для остатка, один отрицательный, а другой положительный; этот выбор определяет, какой из двух последовательных частных должен использоваться для удовлетворения уравнения (1). В теории чисел всегда выбирается положительный остаток, но в вычислениях языки программирования выбирают в зависимости от языка и знаков a или n . [a] Например, стандартный Паскаль и АЛГОЛ 68 дают положительный остаток (или 0) даже для отрицательных делителей, а некоторые языки программирования, такие как C90, оставляют это на усмотрение реализации, когда либо n , либо a отрицательны (подробнее см. таблицу в разделе Языки программирования). a по модулю 0 не определено в большинстве систем, хотя некоторые определяют его как a .
Во многих реализациях используется усеченное деление , для которого частное определяется как
где - функция целой части ( округление к нулю ), т.е. усечение до нулевых значащих цифр. Таким образом, согласно уравнению ( 1 ), остаток имеет тот же знак, что и делимое a, поэтому может принимать 2| n | − 1 значений:
Дональд Кнут [3] продвигает метод деления с минимальным дроблением , для которого частное определяется как
где - функция пола ( округление вниз ). Таким образом, согласно уравнению ( 1 ), остаток имеет тот же знак, что и делитель n :
Рэймонд Т. Бут [4] продвигает евклидово деление , для которого частное определяется как
где sgn — функция знака , — функция пола ( округление вниз ), а — функция потолка ( округление вверх ). Таким образом, согласно уравнению ( 1 ), остаток неотрицателен :
Common Lisp и IEEE 754 используют округленное деление , для которого частное определяется как
где round — функция округления ( округление половины до четного ). Таким образом, согласно уравнению ( 1 ), остаток попадает между и , а его знак зависит от того, с какой стороны от нуля он попадает в эти границы:
Common Lisp также использует деление по потолку , для которого частное определяется как
где ⌈⌉ — функция потолка ( округление вверх ). Таким образом, согласно уравнению ( 1 ), остаток имеет противоположный знак делителя :
Если и делимое, и делитель положительны, то усеченное, уменьшенное и евклидово определения согласуются. Если делимое положительно, а делитель отрицателен, то усеченное и евклидово определения согласуются. Если делимое отрицательно, а делитель положительный, то усеченное и евклидово определения согласуются. Если и делимое, и делитель отрицательны, то усеченное и уменьшенное определения согласуются.
Как описывает Лейен,
Бут утверждает, что евклидово деление превосходит другие с точки зрения регулярности и полезных математических свойств, хотя floored delegate, продвигаемое Кнутом, также является хорошим определением. Несмотря на его широкое использование, усеченное деление, как показано, уступает другим определениям.
— Даан Лейен, «Деление и модуль для компьютерных ученых» [5]
Однако усеченное деление удовлетворяет тождеству . [6]
Некоторые калькуляторы имеют кнопку функции mod() , и многие языки программирования имеют похожую функцию, например, mod( a , n ) . Некоторые также поддерживают выражения, которые используют "%", "mod" или "Mod" в качестве оператора остатка или модуля , например a % n
или a mod n
.
Для сред, в которых отсутствует подобная функция, можно использовать любое из трех приведенных выше определений.
Когда результат операции по модулю имеет знак делимого (усеченное определение), это может привести к неожиданным ошибкам.
Например, чтобы проверить, является ли целое число нечетным , можно попробовать проверить, равен ли остаток от деления на 2 1:
bool is_odd ( int n ) { return n % 2 == 1 ; }
Но в языке, где modulo имеет знак делимого, это неверно, потому что когда n (делимое) отрицательно и нечетно, n mod 2 возвращает −1, а функция возвращает false.
Правильным вариантом является проверка того, что остаток не равен 0 (поскольку остаток 0 одинаков независимо от знаков):
bool is_odd ( int n ) { return n % 2 != 0 ; }
Операции по модулю могут быть реализованы таким образом, что деление с остатком вычисляется каждый раз. Для особых случаев на некоторых аппаратных средствах существуют более быстрые альтернативы. Например, модуль степеней 2 может быть альтернативно выражен как побитовая операция И (предполагая, что x — положительное целое число, или используя необрезающее определение):
x % 2n == x & (2n - 1)
Примеры:
x % 2 == x & 1
x % 4 == x & 3
x % 8 == x & 7
В устройствах и программном обеспечении, которые реализуют побитовые операции более эффективно, чем по модулю, эти альтернативные формы могут привести к более быстрым вычислениям. [7]
Оптимизации компилятора могут распознавать выражения вида expression % constant
, где constant
является степенью двойки, и автоматически реализовывать их как expression & (constant-1)
, позволяя программисту писать более понятный код без ущерба для производительности. Эта простая оптимизация невозможна для языков, в которых результат операции по модулю имеет знак делимого (включая C ), если только делимое не является целочисленным типом без знака . Это связано с тем, что если делимое отрицательно, то и модуль будет отрицательным, тогда как expression & (constant-1)
всегда будет положительным. Для этих языков вместо этого необходимо использовать эквивалентность, выраженную с помощью побитовых операций ИЛИ, НЕ и И.x % 2n == x < 0 ? x | ~(2n - 1) : x & (2n - 1)
Существуют также оптимизации для общих операций с постоянным модулем, в которых сначала вычисляется деление с использованием оптимизации с постоянным делителем .
Некоторые операции по модулю могут быть факторизованы или расширены аналогично другим математическим операциям. Это может быть полезно в криптографических доказательствах, таких как обмен ключами Диффи–Хеллмана . Свойства, включающие умножение, деление и возведение в степень, обычно требуют, чтобы a и n были целыми числами.
Язык | Оператор | Целое число | С плавающей точкой | Определение |
---|---|---|---|---|
АБАП | MOD | Да | Да | Евклидов |
ActionScript | % | Да | Нет | Усеченный |
Ада | mod | Да | Нет | Напольный [8] |
rem | Да | Нет | Усеченный [8] | |
АЛГОЛ 68 | ÷× ,mod | Да | Нет | Евклидов |
АМПЛ | mod | Да | Нет | Усеченный |
АПЛ | | [б] | Да | Да | Напольный |
AppleScript | mod | Да | Нет | Усеченный |
АвтоЛИСП | (rem d n) | Да | Нет | Усеченный |
АВК | % | Да | Нет | Усеченный |
Баш | % | Да | Нет | Усеченный |
БАЗОВЫЙ | Mod | Да | Нет | Зависит от реализации |
до нашей эры | % | Да | Нет | Усеченный |
С С++ | % ,div | Да | Нет | Усеченный [c] |
fmod (С) std::fmod (С++) | Нет | Да | Усеченный [11] | |
remainder (С) std::remainder (С++) | Нет | Да | Округлый | |
С# | % | Да | Да | Усеченный |
Math.IEEERemainder | Нет | Да | Округлый [12] | |
Кларион | % | Да | Нет | Усеченный |
Чистый | rem | Да | Нет | Усеченный |
Кложур | mod | Да | Нет | Напольный [13] |
rem | Да | Нет | Усеченный [14] | |
КОБОЛ | FUNCTION MOD | Да | Нет | Напольный [15] |
FUNCTION REM | Да | Да | Усеченный [15] | |
CoffeeScript | % | Да | Нет | Усеченный |
%% | Да | Нет | Напольный [16] | |
Холодный фьюжн | % ,MOD | Да | Нет | Усеченный |
Общий промежуточный язык | rem (подпись) | Да | Да | Усеченный [17] |
rem.un (без подписи) | Да | Нет | — | |
Общий Лисп | mod | Да | Да | Напольный |
rem | Да | Да | Усеченный | |
Кристалл | % ,modulo | Да | Да | Напольный |
remainder | Да | Да | Усеченный | |
CSS | mod() | Да | Да | Напольный [18] |
rem() | Да | Да | Усеченный [19] | |
Д | % | Да | Да | Усеченный [20] |
Дарт | % | Да | Да | Евклидово [21] |
remainder() | Да | Да | Усеченный [22] | |
Эйфелева | \\ | Да | Нет | Усеченный |
Эликсир | rem/2 | Да | Нет | Усеченный [23] |
Integer.mod/2 | Да | Нет | Напольный [24] | |
Вяз | modBy | Да | Нет | Напольный [25] |
remainderBy | Да | Нет | Усеченный [26] | |
Эрланг | rem | Да | Нет | Усеченный |
math:fmod/2 | Нет | Да | Усеченный (то же, что и C) [27] | |
Эйфория | mod | Да | Нет | Напольный |
remainder | Да | Нет | Усеченный | |
Фа# | % | Да | Да | Усеченный |
Math.IEEERemainder | Нет | Да | Округлый [12] | |
Фактор | mod | Да | Нет | Усеченный |
Файлмейкер | Mod | Да | Нет | Напольный |
Вперед | mod | Да | Нет | Реализация определена |
fm/mod | Да | Нет | Напольный | |
sm/rem | Да | Нет | Усеченный | |
Фортран | mod | Да | Да | Усеченный |
modulo | Да | Да | Напольный | |
Фринк | mod | Да | Нет | Напольный |
Полный БАЗОВЫЙ | MOD | Да | Да | Напольный [28] |
REMAINDER | Да | Да | Усеченный [29] | |
ГЛСЛ | % | Да | Нет | Не определено [30] |
mod | Нет | Да | Напольный [31] | |
Студия GameMaker (GML) | mod ,% | Да | Нет | Усеченный |
GDScript (Годо) | % | Да | Нет | Усеченный |
fmod | Нет | Да | Усеченный | |
posmod | Да | Нет | Евклидов | |
fposmod | Нет | Да | Евклидов | |
Идти | % | Да | Нет | Усеченный [32] |
math.Mod | Нет | Да | Усеченный [33] | |
big.Int.Mod | Да | Нет | Евклидово [34] | |
big.Int.Rem | Да | Нет | Усеченный [35] | |
Круто | % | Да | Нет | Усеченный |
Хаскелл | mod | Да | Нет | Напольный [36] |
rem | Да | Нет | Усеченный [36] | |
Data.Fixed.mod' ( ГХК ) | Нет | Да | Напольный | |
Хаксе | % | Да | Нет | Усеченный |
HLSL | % | Да | Да | Не определено [37] |
Дж. | | [б] | Да | Нет | Напольный |
Ява | % | Да | Да | Усеченный |
Math.floorMod | Да | Нет | Напольный | |
JavaScript TypeScript | % | Да | Да | Усеченный |
Джулия | mod | Да | Да | Напольный [38] |
% ,rem | Да | Да | Усеченный [39] | |
Котлин | % ,rem | Да | Да | Усеченный [40] |
mod | Да | Да | Напольный [41] | |
кш | % | Да | Нет | Усеченный (то же, что и POSIX sh) |
fmod | Нет | Да | Усеченный | |
LabVIEW | mod | Да | Да | Усеченный |
LibreOffice | =MOD() | Да | Нет | Напольный |
Логотип | MODULO | Да | Нет | Напольный |
REMAINDER | Да | Нет | Усеченный | |
Луа 5 | % | Да | Да | Напольный |
Луа 4 | mod(x,y) | Да | Да | Усеченный |
Свобода БАЗОВЫЙ | MOD | Да | Нет | Усеченный |
Маткад | mod(x,y) | Да | Нет | Напольный |
Клен | e mod m (по умолчанию),modp(e, m) | Да | Нет | Евклидов |
mods(e, m) | Да | Нет | Округлый | |
frem(e, m) | Да | Да | Округлый | |
Математика | Mod[a, b] | Да | Нет | Напольный |
МАТЛАБ | mod | Да | Нет | Напольный |
rem | Да | Нет | Усеченный | |
Максима | mod | Да | Нет | Напольный |
remainder | Да | Нет | Усеченный | |
Встроенный язык Maya | % | Да | Нет | Усеченный |
Майкрософт Эксель | =MOD() | Да | Да | Напольный |
Минитаб | MOD | Да | Нет | Напольный |
Модула-2 | MOD | Да | Нет | Напольный |
REM | Да | Нет | Усеченный | |
свинка | # | Да | Нет | Напольный |
Сетевой ассемблер ( NASM , NASMX ) | % , div (без подписи) | Да | Нет | — |
%% (подпись) | Да | Нет | Определено реализацией [42] | |
Ним | mod | Да | Нет | Усеченный |
Оберон | MOD | Да | Нет | Напольный [d] |
Objective-C | % | Да | Нет | Усеченный (то же, что и C99) |
Объект Паскаль , Дельфи | mod | Да | Нет | Усеченный |
OCaml | mod | Да | Нет | Усеченный [43] |
mod_float | Нет | Да | Усеченный [44] | |
Оккам | \ | Да | Нет | Усеченный |
Паскаль (ISO-7185 и -10206) | mod | Да | Нет | Евклидовоподобный [e] |
Перл | % | Да | Нет | Напольный [ж] |
POSIX::fmod | Нет | Да | Усеченный | |
Фикс | mod | Да | Нет | Напольный |
remainder | Да | Нет | Усеченный | |
PHP | % | Да | Нет | Усеченный [46] |
fmod | Нет | Да | Усеченный [47] | |
PIC БАЗОВЫЙ ПРО | \\ | Да | Нет | Усеченный |
ПЛ/И | mod | Да | Нет | Напольный (ANSI PL/I) |
PowerShell | % | Да | Нет | Усеченный |
Программный код ( PRC ) | MATH.OP - 'MOD; (\)' | Да | Нет | Неопределенный |
Прогресс | modulo | Да | Нет | Усеченный |
Пролог (ИСО 1995) | mod | Да | Нет | Напольный |
rem | Да | Нет | Усеченный | |
ЧистыйБазовый | % ,Mod(x,y) | Да | Нет | Усеченный |
ЧистыйСкрипт | `mod` | Да | Нет | Евклидово [48] |
Чистые данные | % | Да | Нет | Усеченный (то же, что и C) |
mod | Да | Нет | Напольный | |
Питон | % | Да | Да | Напольный |
math.fmod | Нет | Да | Усеченный | |
math.remainder | Нет | Да | Округлый | |
Вопрос № | % | Да | Нет | Усеченный [49] |
Р | %% | Да | Да | Напольный [50] |
Ракетка | modulo | Да | Нет | Напольный |
remainder | Да | Нет | Усеченный | |
Раку | % | Нет | Да | Напольный |
RealBasic | MOD | Да | Нет | Усеченный |
Причина | mod | Да | Нет | Усеченный |
Рекс | // | Да | Да | Усеченный |
РПГ | %REM | Да | Нет | Усеченный |
Рубин | % ,modulo() | Да | Да | Напольный |
remainder() | Да | Да | Усеченный | |
Ржавчина | % | Да | Да | Усеченный |
rem_euclid() | Да | Да | Евклидово [51] | |
САС | MOD | Да | Нет | Усеченный |
Скала | % | Да | Да | Усеченный |
Схема | modulo | Да | Нет | Напольный |
remainder | Да | Нет | Усеченный | |
Схема Р 6 РС | mod | Да | Нет | Евклидово [52] |
mod0 | Да | Нет | Округлый [52] | |
flmod | Нет | Да | Евклидов | |
flmod0 | Нет | Да | Округлый | |
Царапать | mod | Да | Да | Напольный |
Семя7 | mod | Да | Да | Напольный |
rem | Да | Да | Усеченный | |
SenseTalk | modulo | Да | Нет | Напольный |
rem | Да | Нет | Усеченный | |
sh (POSIX) (включая bash , mksh и т. д.) | % | Да | Нет | Усеченный (то же, что и C) [53] |
Smalltalk | \\ | Да | Нет | Напольный |
rem: | Да | Нет | Усеченный | |
Щелчок! | mod | Да | Нет | Напольный |
Вращаться | // | Да | Нет | Напольный |
Прочность | % | Да | Нет | Усеченный [54] |
SQL ( SQL:1999 ) | mod(x,y) | Да | Нет | Усеченный |
SQL ( SQL:2011 ) | % | Да | Нет | Усеченный |
Стандартный МЛ | mod | Да | Нет | Напольный |
Int.rem | Да | Нет | Усеченный | |
Real.rem | Нет | Да | Усеченный | |
Стата | mod(x,y) | Да | Нет | Евклидов |
Быстрый | % | Да | Нет | Усеченный [55] |
remainder(dividingBy:) | Нет | Да | Округлый [56] | |
truncatingRemainder(dividingBy:) | Нет | Да | Усеченный [57] | |
Тсл | % | Да | Нет | Напольный |
fmod() | Нет | Да | Усеченный (как C) | |
тчш | % | Да | Нет | Усеченный |
Крутящий момент | % | Да | Нет | Усеченный |
Тьюринг | mod | Да | Нет | Напольный |
Верилог (2001) | % | Да | Нет | Усеченный |
VHDL | mod | Да | Нет | Напольный |
rem | Да | Нет | Усеченный | |
ВимЛ | % | Да | Нет | Усеченный |
Визуальный базовый | Mod | Да | Нет | Усеченный |
Веб-сборка | i32.rem_u , i64.rem_u (без подписи) | Да | Нет | — [58] |
i32.rem_s , i64.rem_s (подпись) | Да | Нет | Усеченный [58] | |
x86 сборка | IDIV | Да | Нет | Усеченный |
XBase++ | % | Да | Да | Усеченный |
Mod() | Да | Да | Напольный | |
Зиг | % ,
| Да | Да | Усеченный [59] |
Доказательство теоремы Z3 | div ,mod | Да | Нет | Евклидов |
Кроме того, многие компьютерные системы предоставляют divmod
функционал, который производит частное и остаток одновременно. Примерами служат инструкция архитектуры x86IDIV
, функция языка программирования C div()
и функция Pythondivmod()
.
Иногда полезно, чтобы результат деления по модулю n лежал не между 0 и n − 1 , а между некоторым числом d и d + n − 1. В этом случае d называется смещением , а d = 1 встречается особенно часто.
Похоже, что для этой операции не существует стандартной нотации, поэтому давайте предварительно будем использовать a mod d n . Таким образом, у нас есть следующее определение: [60] x = a mod d n на всякий случай d ≤ x ≤ d + n − 1 и x mod n = a mod n . Очевидно, что обычная операция по модулю соответствует нулевому смещению: a mod n = a mod 0 n .
Операция по модулю со смещением связана с функцией пола следующим образом:
Чтобы увидеть это, пусть . Сначала покажем, что x mod n = a mod n . В общем случае верно, что ( a + bn ) mod n = a mod n для всех целых чисел b ; таким образом, это верно и в частном случае, когда ; но это означает, что , что мы и хотели доказать. Осталось показать, что d ≤ x ≤ d + n − 1 . Пусть k и r — целые числа, такие что a − d = kn + r с 0 ≤ r ≤ n − 1 (см. Евклидово деление ). Тогда , таким образом . Теперь возьмем 0 ≤ r ≤ n − 1 и прибавим d к обеим сторонам, получив d ≤ d + r ≤ d + n − 1 . Но мы видели, что x = d + r , так что мы закончили.
Модуль со смещением a mod d n реализован в Mathematica как Mod[a, n, d]
. [60]
Несмотря на математическую элегантность деления Кнута и евклидова деления, в языках программирования обычно гораздо чаще встречается усеченное деление по модулю. Лейен предоставляет следующие алгоритмы для вычисления двух делений, заданных усеченным целочисленным делением: [5]
/* Евклидов и Floored divmod, в стиле ldiv() языка C */ typedef struct { /* Эта структура является частью C stdlib.h, но воспроизведена здесь для ясности */ long int quot ; long int rem ; } ldiv_t ; /* Евклидово деление */ inline ldiv_t ldivE ( long numer , long denom ) { /* Языки C99 и C++11 определяют оба эти метода как усечение. */ long q = numer / denom ; long r = numer % denom ; if ( r < 0 ) { if ( denom > 0 ) { q = q - 1 ; r = r + denom ; } else { q = q + 1 ; r = r - denom ; } } return ( ldiv_t ){. quot = q , . rem = r }; } /* Деление с меньшим числом */ inline ldiv_t ldivF ( long numer , long denom ) { long q = numer / denom ; long r = numer % denom ; if (( r > 0 && denom < 0 ) || ( r < 0 && denom > 0 )) { q = q - 1 ; r = r + denom ; } return ( ldiv_t ){. quot = q , . rem = r }; }
Для обоих случаев остаток можно вычислить независимо от частного, но не наоборот. Операции здесь объединены для экономии места на экране, поскольку логические ветви одинаковы.
α|ω
вычисляет остаток при делении на .ω
α
%
должно быть усечено. [9] Стандарты до этого момента оставляли поведение, определяемое реализацией. [10]div
и mod
не подчиняются тождеству деления D = d · ( D / d ) + D % d и, таким образом, в корне нарушены.бинарный оператор % возвращает остаток от деления первого выражения на второе. .... Если оба операнда неотрицательны, то остаток неотрицателен; в противном случае знак остатка определяется реализацией.
Функция
fmod
возвращает значение
x - i * y
для некоторого целого числа
i,
такого, что если
y
не равен нулю, результат имеет тот же знак, что и
x
, и величину, меньшую величины
y
.
{{cite book}}
: CS1 maint: числовые имена: список авторов ( ссылка ){{cite book}}
: CS1 maint: числовые имена: список авторов ( ссылка )X по модулю Y, т. е. XY*INT(X/Y).
Функция остатка, т. е. XY*IP(X/Y).
Если оба операнда неотрицательны, то остаток неотрицателен. Результаты не определены, если один или оба операнда отрицательны.
Оператор % определен только в случаях, когда обе стороны положительны или обе стороны отрицательны. В отличие от C, он также работает с типами данных с плавающей точкой, а также с целыми числами.