Pythonで階乗の計算をする

Pythonで階乗の計算をします。数学の中ではそれ自体も面白いテーマですが、階乗の考え方は場合の数の順列や組み合わせにも応用することができます。mathモジュールには階乗に関してfactorial関数が用意されていますが、自分で作ることができるようになると、応用範囲がより広がります。

Pythonで5の階乗5!を計算する

定義通りに階乗を計算する関数

基本来な考え方

変数numに対してnumの階乗num!を変数valで計算します。

for文を使い自然数の階乗を計算する

  1. num = 5
  2. val = 1
  3. for i in range(num, 1, -1): # for i in range(2,num+1): でもOK
  4. val *= i
  5. print(val)
120

3. 変数valを定義し、6行目で階乗計算するためvalを順次、掛け合わせていきます。掛け算の累積になるので初期値は1にします。

4. num=5から変数iを1つずつ減らして5,4,3,2までループします。コメントしたようにrange(2,num+1)とすると2,3,4,5までループすることができますが、5!=5×4×3×2(×1)という定義に従いました。

mathモジュールのfactorial関数

階乗は数学的にもよく使われる計算なので、多くのモジュールで関数が用意されています。

mathモジュールのfactorial関数を使って階乗を計算する

  1. import math
  2. math.factorial(5)
120

2. factorial関数に求めたい階乗の自然数を引数として指定するだけです。

for文を使って階乗を求める関数にする

#1のプログラムを関数に書き換えます。引数に5を指定すると、5!=120を返します。

for文を使い自然数の階乗を計算する関数

  1. def factorial_for(num):
  2. val = 1
  3. for i in range(num, 1, -1):
  4. val *= i
  5. return val
  6. factorial_for(5)
120

while文を使って階乗を求める関数

#2と同じ考え方でwhile文を使って階乗を計算します。whileループの中でnumを順次減らしながらvalに掛けていきます。

while文を使って階乗を求める

  1. def factorial_while(num):
  2. val = 1
  3. while num: # while num > 1:でもOK
  4. val *= num
  5. num -= 1
  6. return val
  7. factorial_while(5)
120

3. while num:とは、numが0になるまで繰り返すことを示します。つまりnumが0以上である限り繰り返し、0になったところで終了し、戻り値として階乗を返します。コメントした通り、最後に1を掛けても意味がないので、while num > 1:としても5,4,3,2までの積になるので少しだけ、効率的になります。

階乗を計算する関数をforループとwhileループと2つの方法で作成しました。モジュールの組み込み関数を使って階乗を計算する

階乗の応用計算

階乗については、次のような次のような計算ができることが知られています。

${\displaystyle \sum _{n=0}^{\infty }{\frac {1}{n!}}={\frac {1}{1}}+{\frac {1}{1}}+{\frac {1}{2}}+{\frac {1}{6}}+{\frac {1}{24}}+{\frac {1}{120}}+\dotsb =e\fallingdotseq 2.7182818284590452353602874713}$

factorial関数を使えば簡単に計算結果が表示されます。

階乗の逆数和

  1. import math
  2. sigma = 0
  3. for i in range(20):
  4. sigma += 1 / math.factorial(i)
  5. sigma
2.7182818284590455

3. 20項まで計算すると2.7182818284590455とかなりの精度で計算することができます。

この程度の計算であれば、瞬時にしてくれますが、2の階乗は$1\times2$、3の階乗は$1\times2\times3$・・・のように同じ計算を何度もする必要があります。そこで3の階乗の計算の時には2の階乗に3を掛る、というように繰り返すと効率よく計算することができます。

階乗を順次求める計算の効率化

  1. %%time
  2. sigma = 1
  3. factor = 1
  4. for i in range(1,2000):
  5. factor *= i
  6. sigma+=1 / factor
  7. sigma
Wall time: 1.95 ms
2.7182818284590455

2. 階乗和を計算する変数sigmaを定義します。このとき、プログラムを簡単にするため目、0!=1なので、sigmaには初期値として1(1/1)を代入しておきます。

3.  階乗を計算するfactorを定義します。factorは順次整数を掛け算していくので、書庫位置を1としておきます。

この方法で1.で%%timeを指定しておくと、実行時間を計測することができます。少し無駄ですが第2000項まで計算すると、実行時間はわずか1.95ms(0.00195秒)です。ちなみに#4を同様に第2000項まで計算すると275msと100倍以上の差になります。

${\displaystyle \sum _{n=0}^{\infty }{\frac {1}{\left(n+2\right)n!}}={\frac {1}{2}}+{\frac {1}{3}}+{\frac {1}{8}}+{\frac {1}{30}}+{\frac {1}{144}}+\dotsb =1}$

もう一つの階乗の計算

  1. sigma = 1 / 2
  2. factor = 1
  3. for i in range(1, 20):
  4. factor *= i
  5. sigma += 1 / ((i+2)*factor)
  6. sigma
0.9999999999999999

1. 和を計算する変数sigmaを定義します。このとき、計算を簡単にするために、第1項を1/2としておきます。

4. 階乗を順次計算し、5.で累計していきます。

7.  0.9999999999999999と答えがほぼ1になり、正しく計算されたことが分かります。

1!から順次リストにする関数

  1. def factorial_list(num):
  2. factor = [1]
  3. for i in range(1, num+1):
  4. factor.append(factor[-1] * i)
  5. return factor
  6. factorial_20 = factorial_list(20)
  7. factorial_20
[1,
 1,
 2,
 6,
 24,
 120,
 720,
 5040,
 40320,
 ・・・以下略

リスト化した階乗のデータを使った計算

  1. sigma_e = 0
  2. sigma_1 = 0
  3. for i, factor in enumerate(factorial_20):
  4. sigma_e += 1/factor
  5. sigma_1 += 1/((i+2)*factor)
  6. print(sigma_e, sigma_1)
2.7182818284590455 0.9999999999999999