05 April, 2021

負数のモジュロ演算

モジュロ演算とは

モジュロ演算とは整数の割り算実行後のあまりを求める演算です。

A / B = C ... D

AをBで割った結果(商)C、あまりD
のDを求める演算と言うことです。

言い換えると

A = B x C + D

となります。

Pythonの2と3では除算演算子の挙動が違うので注意が必要です。 Python2では除算「/」は整数除算となりますが、Python3では結果は常に小数に なります。Python3での整数除算の演算子は「//」になります。 被除数(割られる数)をm、除数(割る数)をn、とした場合の結果を 以下に示します。 除数と商を掛けてあまりを加えた結果が被除数になれば正しい結果となります。 この場合、被除数、除数ともに正の数であれば1通りですが、 どちらかが負の数になると2通りの結果が考えられます。 下記の結果を見るとCでは除数の半分以下(± n/2)のあまりとなっているように 見えます。 一方、Pythonはあまりの符号が除数と同じになる結果が返されているように見えます。 どちらが正しいとかではなくて、言語による定義が異なる、ということでしょう。 ググって見ると、コンパイラ系はCと同じ結果、JavaもCと同じ、という結果に対し Ruby、CommonLispはPythonと同じ、らしいです。 Cの結果は絶対値最小剰余、Pythonの結果は最小非負剰余というらしいです。

そもそも、なぜこの演算を調べたかというと、base64のパディング「==」が はずされた文字列に4の倍数になるように「=」を追加するために 「"=" * (-len(b64)%4)とすればよい」ということが引っかかったためです。 動きとしては正しいですが直感的には「???」でした。

被除数[m] 除数[n] 商[m/n] あまり[m%n] 検算[n*(m/n)+(m%n)=>m] 言語による結果
13 4 3 1 4 x 3 + 1 => 13 共通
13 -4 -3 1 -4 x -3 + 1 => 13 C
-4 -3 -4 x -4 + (-3) => 13 Python
-13 4 -3 -1 4 x -3 + (-1) => -13 C
-4 3 4 x -4 + 3 => -13 Python
-13 -4 3 -1 -4 x 3 + (-1) => -13 Python/C
4 3 -4 x 4 + 3 => -13

以下、Pythonでの結果です。

>>> (13)/(4)
3
>>> (13)%(4)
1

>>> (13)/(-4)
-4
>>> (13)%(-4)
-3

>>> (-13)/(4)
-4
>>> (-13)%(4)
3

>>> (-13)/(-4)
3
>>> (-13)%(-4)
-1

>>> from __future__ import division
>>> (13)/(4)
3.25
>>> (13)/(-4)
-3.25
>>> (-13)/(4)
-3.25
>>> (-13)/(-4)
3.25

>>> (13)//(4)
3
>>> (13)%(4)
1

>>> (13)//(-4)
-4
>>> (13)%(-4)
-3
>>> (-13)//(4)
-4
>>> (-13)%(4)
3
>>> (-13)//(-4)
3
>>> (-13)%(-4)
-1

Tags: ,