いくらか教えてください(-2) % 5
。私のPythonインタープリターによると3ですが、これについて賢明な説明はありますか?
一部の言語では、結果がマシンに依存する可能性があると読みましたが、よくわかりません。
ところで、ほとんどのプログラミング言語は Python に同意せず、結果を返し-2
ます。モジュラスの解釈に応じて、これは正しいです。ただし、最も合意された数学的定義では、a と b のモジュラスはa / bの除算の(厳密に正の) 残りrであると述べられています。より正確には、定義により0 <= r < bです。
Python インタープリターは正しいです。モジュラスを計算する 1 つの (ばかげた) 方法は、結果の値が 0 と (モジュラス - 1) の間になるまでモジュラスを減算または加算することです。
例: 13 mod 5 = (13 − 5) mod 5 = (13 − 10) mod 5 = 3
またはあなたの場合: −2 mod 5 = (−2 + 5) mod 5 = 3
ネガティブに対するモジュラス演算の結果は、プログラミング言語に依存しているようで、ここにリストがありますhttp://en.wikipedia.org/wiki/Modulo_operation
ドキュメントがバイナリ算術演算で述べているように、Python は次のことを保証します。
整数除算とモジュロ演算子は、次の ID によって接続されます:
x == (x/y)*y + (x%y)
. 整数除算とモジュロは、組み込み関数 divmod(): にも接続されていますdivmod(x, y) == (x/y, x%y)
。
そして本当に、
>>> divmod(-2, 5)
(-1, 3).
この方法の一様性を視覚化する別の方法はdivmod
、小さな数列を計算することです。
>>> for number in xrange(-10, 10):
... print divmod(number, 5)
...
(-2, 0)
(-2, 1)
(-2, 2)
(-2, 3)
(-2, 4)
(-1, 0)
(-1, 1)
(-1, 2)
(-1, 3)
(-1, 4)
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(1, 4)
0 % 5 は 0 のはずですよね?
-1 % 5 は 4 である必要があります。これは、逆方向に進む次の許可された数字だからです (つまり、5 は範囲外なので、5 にすることはできません)。
その論理に従うと、-2 は 3 でなければなりません。
それがどのように機能するかを考える最も簡単な方法は、数値が 0 (含む) と 5 (含まない) の間に収まるまで 5 を足したり引いたりし続けることです。
マシンへの依存についてはよくわかりません。そのような実装を見たことはありませんが、それが行われたことがないとは言えません。
他の回答で説明されているように、負の値を持つモジュロ演算には多くの選択肢があります。一般に、異なる言語 (および異なるマシン アーキテクチャ) では、異なる結果が得られます。
Pythonリファレンスマニュアルによると、
モジュロ演算子は常に、2 番目のオペランドと同じ符号 (またはゼロ) の結果を返します。結果の絶対値は、2 番目のオペランドの絶対値より厳密に小さくなります。
は、Python が選択したものです。基本的にモジュロは、これが常に成り立つように定義されています。
x == (x/y)*y + (x%y)
したがって、 (-2)%5 = -2 - (-2/5)*5 = 3 は理にかなっています
すべての OS とアーキテクチャで、C/C++ のこの mod の動作に依存しないように注意してください。私の記憶が正しければ、次のような C/C++ コードに依存しようとしました。
float x2 = x % n;
x2 を 0 から n-1 の範囲に保つために、ある OS でコンパイルすると負の数が入り込んできましたが、別の OS では問題なく動作します。これは、半分の時間しか発生しなかったため、デバッグに時間がかかりました。
-2 を 5 で割ると 0 になり、余りは 3 になります。これがプラットフォームに大きく依存しているとは思いませんが、もっと変わったことを見てきました。
それは確かに 3 です。剰余算術では、モジュラスは単純に割り算の余りであり、-2 を 5 で割った余りは 3 です。
結果は言語によって異なります。Python は除数の符号を返します。たとえば、c# は被除数の符号を返します (つまり、C# では -2 % 5 は -2 を返します)。
「モジュロ」と「剰余」という用語の間にはよく混同されるようです。
数学では、剰余は常に商と一致するように定義する必要がありa / b == c rem d
ます(c * b) + d == a
。商をどのように丸めるかによって、異なる剰余が得られます。
ただし、モジュロは常に結果を返す必要が0 <= r < divisor
あります。これは、負の整数を許可する場合にのみ、負の無限大への丸めと一致します。除算がゼロに丸められる場合 (これは一般的です)、剰余と剰余は非負の値に対してのみ同等です。
一部の言語 (特に C および C++) では、必要な丸め/剰余の動作が定義されておらず、%
あいまいです。多くの人は、丸めをゼロに向けて定義していますが、モジュロという用語を使用して、剰余がより正確になります。Python は負の無限大に丸められるという点で比較的珍しいため、剰余と剰余は同等です。
Ada はゼロ IIRC に向かって丸めますが、演算子mod
とrem
演算子の両方があります。
C ポリシーは、コンパイラがマシンにとって最も効率的な実装を選択できるようにすることを目的としていますが、少なくとも最近では、IMO は誤った最適化です。優れたコンパイラは、負の数が発生しない場合 (符号なしの型を使用する場合はほぼ確実) に最適化のために同等性を使用できる可能性があります。一方、負の数が発生する可能性がある場合は、ほぼ確実に詳細を気にします。移植性の理由から、丸めや剰余に関係なく、必要な結果が得られるように、非常に慎重に設計された複雑なアルゴリズムやチェックを使用する必要があります。行動。
言い換えれば、この「最適化」による利益はほとんど (常にではないにしても) 錯覚であり、場合によっては非常に現実的なコストがかかるため、誤った最適化です。
1 つの説明は、負の数が2 の補数を使用して格納されることです。Python インタープリターがモジュロ演算を実行しようとすると、符号なしの値に変換されます。そのため、 (-2) % 5 を実行する代わりに、実際には 0xFFFF_FFFF_FFFF_FFFD % 5 を計算します。これは 3 です。