定義によれば、階乗とはある正の整数と、その数以下のすべての正の整数の積のことである。
つまり、ある数の階乗を求めるということは、その数から1までのすべての整数を掛け合わせるということである。
0!は慣例的に1にも等しい。
階乗は、整数の後にエクスクラメーションマークを付けて表します。
5!は5の階乗を表します。
そして、その階乗を計算するために、その数字とそれより小さい整数を1まで掛け合わせるのです。
5! = 5 * 4 * 3 * 2 * 1
5! = 120
これらのルールを念頭に置きながら、このチュートリアルでは、Pythonでループと再帰を使って、整数の階乗を計算する方法を学びます。
まず、ループを使った階乗の計算から始めましょう。
ループを使った階乗の計算
階乗の計算は while ループと for ループの両方を使って行うことができる。
一般的な処理はどちらもよく似ている。
必要なのは、入力としてのパラメータとカウンタだけです。
まずは、for
ループから始めましょう。
def get_factorial_for_loop(n):
result = 1
if n > 1:
for i in range(1, n+1):
result = result * i
return result
else:
return 'n has to be positive'
お気づきかもしれませんが、階乗の定義は与えられた数から1まででしたが、ここでは1からn`まで数えています。
1*2*3*4…*n=n*(n-1)*(n-2)*(n-3)*(n-4)…*(n-(n-1))1*2*3*4…*n=n*(n-1)*(n-2)*(n-3)*(n-4) …*(n-(n-1))
1 * 2 * 3 * 4 … * Ÿ n = n Ÿ (n-1) Ÿ (n-2) Ÿ (n-3) Ÿ (n-4) … * ♪♪♪~
(n-(n-1))`は常に1になります。
つまり、どの方向から数えてもいいということです。
1から始まってnに向かって増加することも、n
から始まって1に向かって減少することもできます。
この関数はパラメータとして、階乗を計算する数を表す n
を受け取ります。
まず、 result
という名前の変数を定義して、その値として 1
を代入します。
なぜ0でなく1を代入するのか?
なぜなら、もし0を代入してしまうと、それ以降の0との掛け算は当然ながら全て巨大な0になってしまうからです。
そして、for
ループを1
からn+1
までの範囲で開始します。
Pythonの範囲は第2引数の前で停止することを忘れないでください。
最後の数字も含めるには、単純に 1
を追加します。
forループの中では、現在の
resultの値と、現在のインデックス
i` を掛け合わせます。
最後に、最終的な result
の値を返します。
それでは、この関数をテストして結果を表示してみましょう。
inp = input("Enter a number: ")
inp = int(inp)
print(f"The result is: {get_factorial_for_loop(inp)}")
ユーザーの入力を得る方法についてもっと知りたい方は、 Python でユーザーの入力を得る を参照してください。
をご覧ください。
ユーザーに入力を促すプロンプトが表示されます。
ここでは 4
で試してみます。
Enter a number: 4
The result is: 24
計算機で結果を確認することができます。
4 は 4 * 3 * 2 * 1
で、結果は 24 です。
それでは、while
ループを使ってどのように階乗を計算するか見てみましょう。
以下は、私たちが修正した関数です。
def get_factorial_while_loop(n):
result = 1
while n > 1:
result = result * n
n -= 1
return result
これは、for
ループとよく似ています。
ただし、今回は n
から 1 に向かって移動しており、数学的な定義に近くなっています。
では、この関数をテストしてみましょう。
inp = input("Enter a number: ")
inp = int(inp)
print(f"The result is: {get_factorial_while_loop(inp)}")
入力としてもう一度4を入力しよう。
コード偽
計算結果は「4 * 3 * 2 * 1」ですが、最終的な結果は前と同じです。
ループを使った階乗の計算は簡単でしたね。
次に、再帰的関数を使った階乗の計算を見てみましょう。
再帰を用いた階乗の計算
再帰関数とは、自分自身を呼び出す関数のことです。
最初は少し難しく感じるかもしれませんが、我慢してください、再帰関数は簡単に理解できることがわかります。
一般的に、すべての再帰的関数は、ベースケースと再帰的ステップの2つの主要なコンポーネントを持っています。
ベースケースは、問題の最小のインスタンスである。
また、ブレーク、つまり値を返して再帰から抜け出すケースもある。
階乗関数で言えば、階乗の最終要素である1を返す場合がベースケースとなる。
ベースケースがない場合や、ベースケースが正しくない場合は、再帰関数が無限に実行され、オーバーフローを起こす可能性があります。
再帰的ステップとは、その名の通り、関数の再帰的な部分で、問題全体をより小さなものに変換するものです。
再帰的なステップが問題を縮小するために失敗した場合、再び再帰は無限に実行することができます。
階乗の再帰的な部分を考えてみよう。
- 5!は、5 * 4 * 3 * 2 * 1`である。
しかし、我々は次のことも知っている。
- 4 * 3 * 2 * 1` は 4!である。
つまり、5!は「5 * 4!」であり、4!は「4 * 3!」である、というように。
ということは、n! = n * (n-1)!
となります。
これが階乗の再帰的なステップになります。
となります。
階乗の再帰は、1になった時点で終了します。
これは私たちの基本的なケースになります。
nが
1以下の場合は
1` を返し、入力が 0 の場合をカバーします。
それでは、再帰的階乗関数を見てみましょう。
Enter a number: 4
The result is: 24
ifブロックが基本ケースを表し、
else` ブロックが再帰的ステップを表しているのがわかると思います。
それでは、この関数をテストしてみましょう。
def get_factorial_recursively(n):
if n <= 1:
return 1
else:
return n * get_factorial_recursively(n-1)
今回は入力として 3 を入力する。
inp = input("Enter a number: ")
inp = int(inp)
print(f"The result is: {get_factorial_recursively(inp)}")
同じ結果が得られます。
でも、今回はちょっと面白いことが行われています。
入力があると、この関数は if
ブロックでチェックし、3 が 1 よりも大きいので else
ブロックにスキップします。
このブロックの中で、 return n * get_factorial_recursively(n-1)
という行があります。
とりあえず現在の n
の値は 3
であることが分かっていますが、 get_factorial_recursively(n-1)
はまだ計算中です。
次に、プログラムは同じ関数をもう一度呼び出しますが、今度は私たちの関数が2をパラメータとして受け取ります。
ifブロックをチェックし、
elseブロックまでスキップして、再び最後の行に遭遇します。
ここで、現在のnの値は
2ですが、プログラムはまだ
get_factorial_recursively(n-1)` を計算する必要があります。
そこで、もう一度関数を呼び出しますが、今度は if
ブロックというか、ベースクラスが 1 を返すことに成功して、再帰から抜け出します。
上と同じパターンで、各関数の結果を返し、現在の結果に前の n
を掛けて、前の関数呼び出しの結果を返します。
つまり、このプログラムは、まず階乗の底(1)に到達し、その後、各ステップで乗算しながら、上へ上へと積み上げていくのである。
また、最終的に n * (n-1)
の結果が返されるまで、関数を1つずつコールスタックから取り除いていきます。
これが、一般的な再帰的関数の動作です。
より複雑な問題では、複数の基本ケースや複数の再帰的ステップを持つ、より深い再帰が必要になるかもしれない。
しかし、今のところ、この単純な再帰は階乗問題を解くのに十分なものです。
Pythonの再帰についてもっと知りたい方は、「Pythonで再帰を理解するためのガイド」をご覧ください! >.
をご覧ください。
結論
今回は、「for」と「while」ループを使った階乗の計算方法について説明しました。
また、再帰とは何か、再帰を使った階乗の計算方法についても学びました。
もし、再帰を楽しんで、もっと練習したいのであれば、再帰を使ってフィボナッチ数列を計算してみてください。
また、私たちの記事について何か質問や感想があれば、コメント欄で気軽にシェアしてください。