プログラミング言語の設計者がモジュロ演算の結果の符号を決定するときに使用される理論的根拠は何ですか?


9

通って行く剰余演算(の違いを探索しながら、私が入った大通りremmod)私が出くわしました:

数学では、剰余演算の結果はユークリッド除算の残りの部分です。ただし、他の規則も可能です。コンピュータと計算機には、数値を保存および表現するさまざまな方法があります。したがって、それらのモジュロ演算の定義は、プログラミング言語や基盤となるハードウェアに依存します。

質問:

  • 通って行くユークリッド除算私は、この操作のremainnderは常に正(または0)であることがわかりました。基盤となるコンピューターハードウェアの制限によって、プログラミング言語の設計者は数学とは異なるものになりますか?
  • すべてのプログラミング言語には、モジュロ演算の結果に応じて符号が付けられる、定義済みまたは未定義のルールがあります。これらのルールを作成する際に採用される根拠は何ですか?基盤となるハードウェアが問題である場合、プログラミング言語とは関係なく、それに応じてルールを変更しないでください。

1
私のコードでは、ほとんどの場合、剰余ではなくモジュロが必要です。残りがそれほど人気が​​ある理由はわかりません。
CodesInChaos 2014年

8
関連違いは何ですか?Remainder vs Modulus-Eric Lippertのブログ(C#デザイナーの1人によるものですが、この決定が行われた後、彼はチームに参加したと思います)
CodesInChaos

1
ウィキペディアの記事(引用した部分以外)を読み続けると、引用した内容がかなりよくわかります。その説明はどうですか?
Robert Harvey

1
関連する質問の1つは、これらの操作のどれが直接CPU命令にマップされるかです。Cでは、実装が定義されています。これは、できるだけ多くのプラットフォームのハードウェアに直接マッピングするというCの哲学に適合しています。したがって、CPU間で異なる可能性のあるものは指定しません。
CodesInChaos 2014年

5
@BleedingFingersプログラミングでは、ゼロに向かう整数除算がよく使用され(-3)/2 == -1ます。この定義は役に立ちます。%この部門の履行に一貫性を持たせたい場合は、C#x == (x/y)*y + x % yでの%使用の定義になります。
CodesInChaos 2014年

回答:


6

最近のすべてのコンピューターのハードウェアは、パフォーマンスに影響を与えない(またはささいな)影響を与えることなく、いずれかの符号のmod操作を実装するのに十分強力です。これは理由ではありません。

ほとんどのコンピューター言語の一般的な期待は、(a div b)* b +(a mod b)= aです。言い換えると、divとmodが一緒に考慮されると、数値をいくつかの部分に分割して、確実に元に戻すことができます。この要件は、C ++標準では明示的です。この概念は、多次元配列のインデックス付けと密接に関連しています。よく使っています。

これから、bが正の場合(通常の場合)、divとmodはaの符号を保持することがわかります。

一部の言語は、modに関連する「rem()」関数を提供し、他のいくつかの数学的な正当化があります。私はこれを使用する必要がありませんでした。たとえば、Gnu Cのfrem()を参照してください。[編集]


それがポジティブであるか、ポジティブでない場合、それはrem(a,b)もっとリクライであると思います。mod(a,b)mod(a,b) + b
user40989 2014

3
(a div b) * b + (a mod b) = a-これ、とても。実際には、ウィキペディアの記述方法に反しユークリッド部門の負の数にそれを拡張(特に「残りはマイナスになることはありません4つの番号のうちの1つにすぎない。」)私がしたため、私を混乱させる常に残りがいることを教えすることができ陰性であることそのレベルのすべての数学のクラスで。
イズカタ

@ user40989:使ったことがないと言った。編集を参照してください!
david.pfx 2014

4

通常、プログラミングにはX == (X/n)*n + X%n、したがって、モジュロの定義方法は、整数除算の定義方法によって異なります。

これを念頭に置いて、「プログラミング言語の設計者が整数除算の動作を決定するときに使用される根拠は何ですか?

実際には約7つの選択肢があります。

  • 負の無限大に丸める
  • 正の無限大に丸める
  • ゼロに丸める
  • 「最も近い値に丸める」のいくつかのバージョン(0.5などの丸め方法の違い)

今考えなさい-( (-X) / n) == X/n。他のものは一貫していないように見えますが(浮動小数点の場合は真実です)、非論理的(バグの原因となる可能性があり、最適化の失敗の可能性もあります)。このため、整数除算の最初の2つの選択肢(どちらかの無限大に丸める)は望ましくありません。

特に「ビットマップへの丸め」の選択は、特にビットマップのようなもの(たとえばoffset = index / 8; bitNumber = index%8;)を実行している場合に、プログラミングにとって頭痛の種です。

これにより、「最も健全な可能性がある」選択肢としてゼロへの丸めが残ります。これは、moduloが分子(またはゼロ)と同じ符号の値を返すことを意味します。

注:また、ほとんどのCPU(私が認識しているすべてのCPU)が整数の除算を同じ「ゼロに丸める」方法で行うことにも注意してください。これは同じ理由である可能性があります。


ただし、切り捨てによる除算にも独自の不整合があります。それは(a+b*c)/b == a % b、とが壊れているa >> n == a / 2 ** nため、フロアされた除算には正常な動作があります。
dan04

最初の例では意味がありません。2番目の例はプログラマーの混乱です。正のaと正のnは一貫性があり、負のaと正のnは右シフトの定義方法(算術と論理)に依存し、負のnは壊れます(例:)1 >> -2 == a / 2 ** (-2)
ブレンダン

最初の例はタイプミスでした(a + b * c) % b == a % b。つまり、%演算子は被除数で除数周期的であり、しばしば重要です。たとえば、床分割のday_count % 7場合は曜日が表示されますが、切り捨て分割の場合は、これはエポックより前の日付では機能しません。
dan04

0

まず、モジュロbはa-b *(a div b)と等しくなければならないことを繰り返します。言語がそれを提供しない場合、あなたはひどい数学的混乱に陥っています。その式a-b *(a div b)は、実際にはbを法としてaを計算する実装の数です。

いくつかの可能な根拠があります。1つ目は、最高速度が必要なことです。そのため、div bは、使用するプロセッサーが提供するものとして定義されます。プロセッサに「div」命令がある場合、div bはdiv命令が実行するものです(それがまったく正気ではない限り)。

2つ目は、特定の数学的な動作が必要なことです。最初にb> 0と仮定します。divbの結果をゼロに丸めるのはかなり合理的です。したがって、4 div 5 = 0、9 div 5 = 1、-4 div 5 = -0 = 0、-9 div 5 = -1となります。これにより、(-a)div b =-(a div b)および(-a)modulo b =-(a modulo b)が得られます。

これはかなり合理的ですが、完璧ではありません。たとえば、(a + b)div b =(a div b)+ 1は、a = -1の場合、成り立たない。固定されたb> 0の場合、通常、(b)aには可能な値があり、a div bが同じ結果を出しますが、2b-1の値aが-b + 1からb-1まであり、a div bが0に等しい場合を除きます。また、aが負の場合、bを法とする剰余も負になることを意味します。モジュロbは常に0からb-1の範囲の数値である必要があります。

一方、aの連続する値を通過するときに、aを法とするaが0からb-1までの値を通過してから、再び0で始まるように要求することも非常に合理的です。そして、(a + b)div bが(a div b)+ 1であることを要求するには、div bの結果を-無限大に丸める必要があるため、-1 div b = -1とします。繰り返しますが、欠点もあります。(-a)div b =-(a div b)は成立しません。2または任意の数b> 1で繰り返し除算しても、最終的に0の結果は得られません。

対立があるので、言語は彼らにとってどの利点のセットがより重要であるかを決定し、それに応じて決定しなければなりません。

負のbの場合、ほとんどの人は最初にa div bとaを法とするaがどうあるべきか頭をつかむことができないため、簡単な方法はdiv b =(-a)div(-b)とaモジュロb =(-a)b <0の場合はモジュロ(-b)、または正のbのコードを使用した自然な結果。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.