コンピューターにおいて、モジュロ演算は、ある数値を別の数値で割った後の剰余または符号付き剰余を返します。この剰余は、演算の モジュラスと呼ばれます。
2つの正の数aとn が与えられたとき、nを法とするa(しばしば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です( a mod 1 は常に 0 であり、a mod 0は未定義で、ゼロ除算です)。
aまたはnのいずれかが負の場合、基本的な定義は崩れ、プログラミング言語によってこれらの値の定義方法が異なります。
定義のバリエーション
数学では、モジュロ演算の結果は同値類であり、そのクラスの任意のメンバーを代表として選択できます。ただし、通常の代表は最小の正の剰余、つまりそのクラスに属する最小の非負の整数です(つまり、ユークリッド除算の余り)。[2]ただし、他の規則も可能です。コンピュータと計算機には、数値を保存および表現するさまざまな方法があるため、モジュロ演算の定義はプログラミング言語または基礎となるハードウェアによって異なります。
ほぼすべてのコンピューティング システムでは、 aをnで割った商qと余りrは次の条件を満たします。
この場合も、剰余がゼロでない場合は符号の曖昧さが残ります。剰余には 2 つの選択肢があり、一方は負で他方は正です。この選択によって、連続する 2 つの商のうちどちらを使用して式 (1) を満たす必要があるかが決まります。整数論では正の剰余が常に選択されますが、コンピューティングでは、プログラミング言語は言語とaまたはnの符号に応じて選択します。[a]たとえば、標準のPascalおよびALGOL 68では、負の除数に対しても正の剰余 (または 0) が返され、C90 などの一部のプログラミング言語では、nまたはaのいずれかが負の場合に実装に任せます (詳細については § プログラミング言語での表を参照)。 0 を法とするaはほとんどのシステムで未定義ですが、一部のシステムではaとして定義されています。

商(q)と 切り捨て除算を用いた剰余(r)を被除数(a )の関数として表す 多くの実装では切り捨て除算が使用され、その商は次のように定義されます。
ここで、は整数部関数(ゼロへの丸め)、すなわちゼロ有効桁への切り捨てである。したがって、式( 1 )によれば、剰余は被除数aと同じ符号を持つので、 2| n | − 1の値をとることができる。

切り捨て除算による商と余り ドナルド・クヌース[3]は、底辺除算を提唱しており、その商は次のように定義される。
ここで は切り捨て関数(切り捨て)である。したがって、式( 1 )によれば、剰余は除数nと同じ符号を持つ。

ユークリッド除算による商と余り レイモンド・T・ブーテ[4]はユークリッドの除算を提唱しており、その商は次のように定義される。
ここでsgnは符号関数、は切り捨て関数(切り捨て)、は切り上げ関数(切り上げ)である。したがって式( 1 )によれば、剰余は負ではない。

四捨五入による商と余り Common LispとIEEE 754では丸め除算が使用され、その商は次のように定義されます。
ここで、roundは丸め関数(半分を偶数に丸める)である。したがって、式( 1 )によれば、剰余はとの間に位置し、その符号は、これらの境界内でゼロのどちら側に位置するかによって決まる。

天井割り算による商と余り Common Lispでは天井割り算も使用されており、その商は次のように定義されます。
ここで、⌈⌉は天井関数(切り上げ)である。したがって、式(1)によれば、余りは除数の符号と反対の符号を持つ。
被除数と除数が両方とも正の場合、切り捨て、切り捨て、およびユークリッドの定義は一致します。被除数が正で除数が負の場合、切り捨てとユークリッドの定義は一致します。被除数が負で除数が正の場合、切り捨てとユークリッドの定義は一致します。被除数が負で除数が正の場合、切り捨てとユークリッドの定義は一致します。被除数と除数が両方とも負の場合、切り捨てと切り捨ての定義は一致します。
ライエン氏が述べたように、
ブーテは、ユークリッド除算は規則性と有用な数学的特性の点で他の除算よりも優れていると主張しているが、クヌースが提唱する切り捨て除算も優れた定義である。広く使用されているにもかかわらず、切り捨て除算は他の定義よりも劣っていることがわかっている。
— ダーン・ライジェン『コンピュータ科学者のための除算と剰余』[5]
しかし、切り捨て除算は恒等式を満たす。[6]
表記
一部の計算機にはmod()関数ボタンがあり、多くのプログラミング言語には、たとえばmod( a , n )と表現される同様の関数があります。また、またはのように、剰余演算子として「%」、「mod」、または「Mod」を使用する式をサポートするものもあります。
a % na mod n
同様の機能がない環境では、上記の 3 つの定義のいずれかを使用できます。
よくある落とし穴
モジュロ演算の結果に被除数の符号(切り捨て定義)が含まれる場合、予期しない間違いが発生する可能性があります。
たとえば、整数が奇数かどうかをテストするには、2 による余りが 1 に等しいかどうかをテストする傾向があります。
bool is_odd ( int n ) {戻り値n % 2 == 1 ; }
しかし、モジュロが被除数の符号を持つ言語では、これは誤りです。なぜなら、n (被除数) が負で奇数の場合、n mod 2 は -1 を返し、関数は false を返すからです。
正しい代替案の 1 つは、余りが 0 でないことをテストすることです (余り 0 は符号に関係なく同じであるため)。
bool is_odd ( int n ) {戻り値n % 2 != 0 ; }
パフォーマンスの問題
モジュロ演算は、剰余のある除算が毎回計算されるように実装される場合があります。特殊なケースでは、一部のハードウェアでは、より高速な代替手段が存在します。たとえば、2 の累乗のモジュロは、ビット単位のAND 演算として表現することもできます( x が正の整数であると仮定するか、切り捨てのない定義を使用します)。
x % 2n == x & (2n - 1)
例:
x % 2 == x & 1x % 4 == x & 3x % 8 == x & 7
モジュロよりも効率的にビット演算を実装するデバイスやソフトウェアでは、これらの代替形式により計算が高速化される可能性があります。[7]
コンパイラの最適化では、が 2 の累乗expression % constantである形式の式を認識し、 として自動的に実装することで、プログラマがパフォーマンスを犠牲にすることなく、より明確なコードを記述できるようにします。この単純な最適化は、被除数が符号なし整数型でない限り、モジュロ演算の結果に被除数の符号が含まれる言語 ( Cを含む) では不可能です。これは、被除数が負の場合、モジュロは負になるのに対し、は常に正になるためです。これらの言語では、代わりにビット単位の OR、NOT、AND 演算を使用して表現される等価性を使用する必要があります。
constantexpression & (constant-1)expression & (constant-1)x % 2n == x < 0 ? x | ~(2n - 1) : x & (2n - 1)
定数除数最適化を使用して最初に除算を計算することによって、一般的な定数係数演算の最適化も存在します。
プロパティ(アイデンティティ)
一部のモジュロ演算は、他の数学演算と同様に因数分解または展開できます。これは、 Diffie-Hellman 鍵交換などの暗号化証明で役立ちます。乗算、除算、累乗を含むプロパティでは、通常、aとnが整数である必要があります。
- 身元:
- 逆:
- 分配法:
- ( a + b ) mod n = [( a mod n ) + ( b mod n )] mod n。
- ab mod n = [( a mod n )( b mod n )] mod n。
- 部門(定義): 1つの/b mod n = [( a mod n )( b −1 mod n )] mod n、右辺が定義されている場合(つまり、 bとnが互いに素である場合)、それ以外の場合は未定義です。
- 逆乗算: [( ab mod n )( b −1 mod n )] mod n = a mod n。
プログラミング言語では
さらに、多くのコンピュータ システムではdivmod、商と余りを同時に生成する機能が提供されています。例としては、x86 アーキテクチャのIDIV命令、C プログラミング言語のdiv()関数、Pythonのdivmod()関数などがあります。
一般化
オフセット付きモジュロ
場合によっては、 n を法とした演算の結果が0 とn − 1 の間ではなく、ある数値dとd + n − 1の間にあると便利なことがあります。その場合、d はオフセットと呼ばれ、d = 1が特に一般的です。
この演算には標準的な表記法がないようですので、とりあえずa mod d nを使用します。したがって、次の定義が得られます。[57] d ≤ x ≤ d + n − 1かつx mod n = a mod nの場合、x = a mod d n。明らかに、通常のモジュロ演算はゼロオフセットに対応します:a mod n = a mod 0 n。
オフセットによる剰余演算は、次のようにfloor 関数と関連しています。
これを確かめるために、 とします。まず、x mod n = a mod nであることを示します。一般に、すべての整数bに対して( a + bn ) mod n = a mod nは真です。したがって、 の特定のケースでもこれは真ですが、これは であることを意味し、これが証明したかったことです。d ≤ x ≤ d + n − 1であることがまだ証明されていません。kおよびrを、 0 ≤ r ≤ n − 1でa − d = kn + rとなる整数とします(ユークリッドの除算を参照)。すると となり、したがって となります。ここで0 ≤ r ≤ n − 1を取り、両辺にd を加えると、 ≤ d + r ≤ d + n − 1が得られます。しかし、 x = d + rであることはすでに確認したので、これで終わりです。
オフセットa mod d nの法はMathematicaでは次のように実装されていますMod[a, n, d] 。[57]
切り捨てを使用した他の剰余定義の実装
クヌースの床割り算とユークリッド割り算は数学的に優雅であるにもかかわらず、プログラミング言語では一般に切り捨て割り算に基づく剰余がはるかに一般的です。ライエンは切り捨て整数割り算を与えられた2つの割り算を計算するための次のアルゴリズムを提供しています: [5]
/* C の ldiv() スタイルのユークリッドおよび Floored divmod */
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 }; }
どちらの場合も、剰余は商とは独立して計算できますが、その逆はできません。論理分岐は同じなので、ここでは画面スペースを節約するために演算が結合されています。
参照
- モジュロ (曖昧さ回避) –モジュロという単語はさまざまな用途で使われていますが、そのすべては1801 年にカール F. ガウスがモジュラー演算を導入したことに由来しています。
- モジュロ (数学)、数学における用語の一般的な使用法
- モジュラー指数
- 回転(角度)
注記
- ^数学的には、これら 2 つの選択肢は、 余りが満たされる不等式に使用可能な無限の選択肢のうちの 2 つにすぎません。
- ^ ab 引数の順序が逆になります。つまり、で割ったときの剰余
α|ωを計算します。ωα - ^ C99とC++11では、の振る舞いは
%切り捨てられると定義されています。[9]それ以前の標準では、その振る舞いは実装定義のままでした。[10] - ^ 除数は正の数でなければなりません。それ以外の場合は未定義です。
- ^ Boute が論じたように、ISO Pascal のとの定義は
divD = d · ( D / d ) + D % dmodの除算恒等式に従わず、根本的に破綻しています。 - ^ Perlは通常、機種に依存しない算術モジュロ演算子を使用します。例と例外については、乗法演算子に関するPerlのドキュメントを参照してください。[43]
参考文献
- ^ Weisstein, Eric W. 「Congruence」。Wolfram MathWorld . 2020年8月27日閲覧。
- ^ Caldwell, Chris. 「残留物」。Prime Glossary 。 2020年8月27日閲覧。
- ^ Knuth, Donald. E. (1972). The Art of Computer Programming . Addison-Wesley.
- ^ Boute, Raymond T. (1992 年 4 月). 「関数 div と mod のユークリッド定義」. ACM Transactions on Programming Languages and Systems . 14 (2). ACM Press (New York, NY, USA): 127–144. doi :10.1145/128861.128862. hdl : 1854/LU-314490 . S2CID 8321674.
- ^ ab Leijen, Daan (2001 年 12 月 3 日). 「コンピュータ科学者のための除算と剰余」(PDF) 。2014 年 12 月 25 日閲覧。
- ^ Peterson, Doctor (2001年7月5日). 「Mod関数と負の数」.数学フォーラム - Ask Dr. Math . 2019年10月22日時点のオリジナルよりアーカイブ。 2019年10月22日閲覧。
- ^ Horvath, Adam (2012 年 7 月 5 日)。「より高速な除算と剰余演算 - 2 の累乗」。
- ^ ab ISO/IEC 8652:2012 - 情報技術 - プログラミング言語 - Ada。ISO、IEC。2012。sec.4.5.5乗算演算子。
- ^ 「C99仕様(ISO/IEC 9899:TC2)」(PDF)。2005年5月6日。6.5.5項「乗算演算子」 。 2018年8月16日閲覧。
- ^ ISO/IEC 14882:2003: プログラミング言語 – C++。国際標準化機構(ISO)、国際電気標準会議(IEC)。2003 年。5.6.4 節。
バイナリ % 演算子は、最初の式を 2 番目の式で割った余りを生成します。.... 両方のオペランドが非負の場合、余りは非負です。そうでない場合、余りの符号は実装定義です。
- ^ ISO/IEC 9899:1990: プログラミング言語 – C . ISO , IEC . 1990. sec. 7.5.6.4.
fmod
関数は、
y
がゼロ以外の場合
、結果の符号が
xと同じで、絶対値が
y
より小さい
整数
i
に対して、値
x - i * y
を返します。
- ^ ab dotnet-bot. 「Math.IEEERemainder(Double, Double) メソッド (システム)」。Microsoft Learn。2022年 10 月 4 日閲覧。
- ^ 「clojure.core - Clojure v1.10.3 API ドキュメント」。clojure.github.io 。2022年 3 月 16 日閲覧。
- ^ 「clojure.core - Clojure v1.10.3 API ドキュメント」。clojure.github.io 。2022年 3 月 16 日閲覧。
- ^ ab ISO/IEC JTC 1/SC 22/WG 4 (2023年1月). ISO/IEC 1989:2023 – プログラミング言語 COBOL . ISO .
{{cite book}}: CS1 maint: 数値名: 著者リスト (リンク) - ^ CoffeeScript 演算子
- ^ ISO/IEC JTC 1/SC 22 (2012 年 2 月). ISO/IEC 23271:2012 — 情報技術 — 共通言語インフラストラクチャ (CLI). ISO . §§ III.3.55–56.
{{cite book}}: CS1 maint: 数値名: 著者リスト (リンク) - ^ 「式 - Dプログラミング言語」dlang.org . 2021年6月1日閲覧。
- ^ 「operator % method - num class - dart:core library - Dart API」。api.dart.dev 。 2021年6月1日閲覧。
- ^ 「剰余メソッド - num クラス - dart:core ライブラリ - Dart API」。api.dart.dev。2021年 6 月 1 日閲覧。
- ^ 「カーネル — Elixir v1.11.3」hexdocs.pm . 2021年1月28日閲覧。
- ^ 「Integer — Elixir v1.11.3」hexdocs.pm . 2021年1月28日閲覧。
- ^ 「Basics - core 1.0.5」. package.elm-lang.org . 2022年3月16日閲覧。
- ^ 「Basics - core 1.0.5」. package.elm-lang.org . 2022年3月16日閲覧。
- ^ 「Erlang -- math」. erlang.org . 2021年6月1日閲覧。
- ^ ANSI (1987年1月28日). プログラミング言語 - フルBASIC. ニューヨーク: アメリカ規格協会. § 5.4.4.
X modulo Y、すなわち、XY*INT(X/Y)。
- ^ ANSI (1987年1月28日). プログラミング言語 - フルBASIC. ニューヨーク: アメリカ規格協会. § 5.4.4.
剰余関数、すなわちXY*IP(X/Y)。
- ^ 「GLSL 言語仕様、バージョン 4.50.7」(PDF)。セクション 5.9 式。
両方のオペランドが非負の場合、余りは非負になります。オペランドの 1 つまたは両方が負の場合、結果は未定義です。
- ^ 「GLSL 言語仕様、バージョン 4.50.7」(PDF)。セクション 8.3 共通関数。
- ^ 「Goプログラミング言語仕様 - Goプログラミング言語」。go.dev 。 2022年2月28日閲覧。
- ^ 「math パッケージ - math - pkg.go.dev」。pkg.go.dev 。2022年 2 月 28 日閲覧。
- ^ 「big package - math/big - pkg.go.dev」。pkg.go.dev 。 2022年2月28日閲覧。
- ^ 「big package - math/big - pkg.go.dev」。pkg.go.dev 。 2024年4月12日閲覧。
- ^ ab 「6 定義済み型とクラス」www.haskell.org . 2022年5月22日閲覧。
- ^ 「演算子」。Microsoft 。 2021年7月19日閲覧。
% 演算子は、両辺が正か両辺が負の場合にのみ定義されます。C とは異なり、整数だけでなく浮動小数点データ型でも動作します。
- ^ 「数学 · Julia 言語」. docs.julialang.org . 2021 年 11 月 20 日閲覧。
- ^ 「数学 · Julia 言語」. docs.julialang.org . 2021 年 11 月 20 日閲覧。
- ^ 「rem - Kotlinプログラミング言語」Kotlin . 2021年5月5日閲覧。
- ^ 「mod - Kotlinプログラミング言語」Kotlin . 2021年5月5日閲覧。
- ^ 「第3章: NASM言語」NASM - The Netwide Assembler バージョン 2.15.05。
- ^ 「OCamlライブラリ:Stdlib」。ocaml.org 。 2022年2月19日閲覧。
- ^ 「OCamlライブラリ:Stdlib」。ocaml.org 。 2022年2月19日閲覧。
- ^ Perl ドキュメント
- ^ 「PHP: 算術演算子 - マニュアル」。www.php.net 。 2021年11月20日閲覧。
- ^ 「PHP: fmod - マニュアル」。www.php.net 。 2021年11月20日閲覧。
- ^ 「ユークリッド環」.
- ^ QuantumWriter. 「Expressions」. docs.microsoft.com . 2018 年 7 月 11 日閲覧。
- ^ 「R: 算術演算子」. search.r-project.org . 2022年12月24日閲覧。
- ^ 「F32 - 錆」.
- ^ r6rs.orgより
- ^ 「シェルコマンド言語」。pubs.opengroup.org 。 2021年2月5日閲覧。
- ^ 「Apple Developer Documentation」。developer.apple.com 。 2021年11月20日閲覧。
- ^ 「Apple Developer Documentation」。developer.apple.com 。 2021年11月20日閲覧。
- ^ 「Apple Developer Documentation」。developer.apple.com 。 2021年11月20日閲覧。
- ^ ab Rossberg, Andreas 編 (2022 年 4 月 19 日). 「WebAssembly コア仕様: バージョン 2.0」. World Wide Web Consortium . § 4.3.2 整数演算。
- ^ 「Zig ドキュメント」。Zigプログラミング言語。2022年 12 月 18 日閲覧。
- ^ ab "Mod". Wolfram言語およびシステムドキュメントセンター. Wolfram Research . 2020年. 2020年4月8日閲覧。
外部リンク
- さまざまな種類の整数除算
- Modulorama、掛け算表の循環表現のアニメーション(フランス語での説明)
