『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

剰余演算

剰余演算

$a$ を $b$ で割ったときの 剰余 (modulo) $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 では算術演算子 % を使って 剰余(余り) を取得することができます。

# PYTHON_MOD_01

# In[1]

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

任意の数値 a を渡して偶奇を判定する関数を定義してみます。a が整数に限定されている場合は 2 で割ったときの剰余が 0 の場合とそれ以外で条件分枝させればよいのですが、記事の冒頭でも述べたように、Python の剰余演算は a が非整数でも実行されるので、剰余が 0, 1, それ以外というように分枝させる必要があります。

# In[2]

# 偶奇判定関数
def even_odd(a):

    # aを2で割った余りが0ならばeven number(偶数)
    if a % 2 == 0:
        msg = "even number"

    # aを2で割った余りが1ならばodd number(奇数)
    elif a % 2 == 1:
        msg = "odd number"

    # それ以外は非整数(non-integer number)
    else:
        msg = "non-integer number"
    return msg

引数 a に 6 を渡すと “even number” が返ります。

# In[3]

# 6の偶奇を調べる
even_odd(6)
'even number'

引数 a に 11 を渡すと “odd number” が返ります。

# In[4]

# 11の偶奇を調べる
even_odd(11)
'odd number'

引数 a に 15.5 を渡すと、15.5 は整数ではないので、”non-integer number” が返ります。

# In[5]

# 15.5の偶奇を調べる
even_odd(15.5)
'non-integer number'

ちなみに、0 は偶数です。

# In[6]

# 0の偶奇を調べる
even_odd(0)
'even number'

divmod()

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

# PYTHON_MOD_02

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

print(x)
(6, 3)

numpy.mod()

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

# PYTHON_MOD_03

# 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 で割った剰余を計算します。

# PYTHON_MOD_04

# 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() は被除数に等しい符号の剰余を返します。

# PYTHON_MOD_05

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

# numpy.fmod()による -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$ となる要素だけを抜き出したいときには、配列のマスキング機能を使って次のようなコードを記述します。

# PYTHON_MOD_06

# 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$ となる数の集合)に分類します。

# PYTHON_MOD_07

# 乱数シードを設定
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]

コメント

  1. HNaito より:

    下記は誤植と思われますので、ご確認ください。
     
    MOD_05 プログラムの 6 行目で、numpy.mod( ) → numpy.fmod( )