剰余演算

剰余演算

剰余演算の定義

 $a$ を $b$ で割ったときの剰余 $r$ は
 
\[a=bq+r\quad (0\leq r\leq |b|)\]
によって定義され、
 
\[r=a\ \mathrm{mod}\ b\]
と表します。$q$ は商です。Python においては $q$ だけが(浮動小数点数型の)整数値であり、$a,\ b,\ r$ は必ずしも整数値であるとは限りません。たとえば、$13.5$ を $5.5$ で割る場合、
 
\[13.5=5.5\times 2+2.5\]
と書けるので、剰余は $13.5\ \mathrm{mod}\ 5.5=2.5$ となります。

 ≫ 剰余演算に関する詳細はこちらのサイトの数論講座を参照してください
 

算術演算子 %

 Python では算術演算子 % を使って 剰余(余り)を取得することができます。

# 算術演算子による剰余演算

r1 = 35 % 6
r2 = 13.5 % 3
r3 = -10.5 % 2.0

print("35 mod 6 = {}".format(r1))
print("13.5 mod 3 = {}".format(r2))
print("-10.5 mod 2.0 = {}".format(r3))
35 mod 6 = 5
13.5 mod 3 = 1.5
-10.5 mod 2.0 = 1.5

 

divmod()

 組み込み関数の divmod() を使うと、商と剰余 を同時に取得することができます。

# 45÷7の商と剰余を取得
x = divmod(45, 7)

print(x)
(6, 3)

 

NumPy関数を用いた剰余演算

numpy.mod()

 numpy.mod(x, a)x mod a を返します。第 1 引数 x に配列、第 2 引数に数値が与えられた場合、x の各要素について a で割った剰余を計算します。

# NumPyをインポート
import numpy as np

# x=[1 2 3 4 5 6 7 8 9]
x = np.arange(1, 10)

# xの各要素について、2 で割った剰余を計算
r = np.mod(x, 2)

print(r)
[1 0 1 0 1 0 1 0 1]

 

numpy.fmod()

 numpy.fmod(x, a)x mod a を返します。第 1 引数 x に配列、第 2 引数に数値が与えられた場合、x の各要素について a で割った剰余を計算します。

# NumPyをインポート
import numpy as np

# x=[1 2 3 4 5 6 7 8 9]
x = np.arange(1, 10)

# xの各要素について、2 で割った剰余を計算
r = np.fmod(x, 2)

print(r)
[1 0 1 0 1 0 1 0 1]

 

numpy.mod()とnumpy.fmod()の相違点

 numpy.mod() は除数に等しい符号の剰余を返しますが、numpy.fmod() は被除数に等しい符号の剰余を返します。

# numpy.mod()による -11 mod 5 の演算
r_mod = np.mod(-11, 5)

# numpy.mod()による -11 mod 5 の演算
r_fmod = np.fmod(-11, 5)

print("r_mod = {}".format(r_mod))
print("r_fmod = {}".format(r_fmod))
r_mod = 4
r_fmod = -1

 すなわち、numpy.mod() は
 
\[-11=5\times (-3)+4\]
という式で剰余 $4$ を計算しているのに対し、numpy.fmod() は
 
\[-11=5\times (-2)+(-1)\]
という式で剰余 $-1$ を計算していることを意味します。
 

剰余演算の応用

 たとえば、ある配列から 4 で割ったときの余りが $1$ となる要素だけを抜き出したいときには、配列のマスキング機能を使って次のようなコードを記述します。

# NumPyをnpという名前でインポート
import numpy as np

# x=[1 2 3 4 5 6 7 8 9 10 11 12]
x = np.arange(1, 13)

# 4で割ったときの余りが 
y = x[np.mod(x, 4) == 1]

print(y)
[1 5 9]

 
 さらに応用すると、配列の要素をある数で割った余りによって分類することができます(このように分類された集合を剰余類とよびます)。以下のコードでは、$1$~$100$ の整数乱数を $20$ 個生成して、$4k,\ 4k+1,\ 4k+2,\ 4k+3$ 型(すなわち $4$ で割った余りがそれぞれ $0,\ 1,\ 2,\ 3$ となる数の集合)に分類します。

# 乱数シードを設定
np.random.seed(0)

# 1~100の整数乱数を20個生成
x = np.random.randint(1, 100, 20)

# 配列xの要素数
n = x.shape[0]

# 配列xを4k,4k+1,4k+2,4k+3に分類
for i in range(4):
    y = x[np.fmod(x, 4) == i]
    print("4k+{}型 : {}".format(i, y))
4k+0型 : [48 68 68 84 88 40 88]
4k+1型 : [45 65 37 89 89 13 89]
4k+2型 : [10 22 66]
4k+3型 : [71 59 47]