Pythonで「階乗(n!)を求める15の方法」を詳しく解説!

PRについて
※このサイトはアフィリエイト広告(Amazonアソシエイト含む)を掲載しています。
スポンサーリンク
※このサイトはアフィリエイト広告(Amazonアソシエイト含む)を掲載しています。
Pythonで「階乗(n!)を求める15の方法」を詳しく解説! 統計学
Pythonで「階乗(n!)を求める15の方法」を詳しく解説!
統計学入門

階乗(factorial)は、数学や統計学で頻繁に登場する基本的な計算です。

記号としては n! と表され、1からその数 n までの整数を掛け合わせた結果を意味します。

たとえば、以下のように計算されます:

 5!=5×4×3×2×1=120

階乗は、組み合わせの計算、確率分布、アルゴリズムの設計など、さまざまな場面で利用されます。

本記事では、Pythonを使って階乗を計算する多様な方法を解説します。

ごまこ
ごまこ

階乗は確率、統計を学んでいく上で様々な場面で出会いますね!
Pythonで計算する方法はたくさんあるんですか?

ごまお
ごまお

Pythonの基礎文法やアルゴリズムで実行する方法もあれば、ライブラリを使う方法もたくさんありますよ!
今回は考え方で分けつつ、合計15個の実行方法を教えますね!

2. 基本的な実装方法

再帰を使った実装

階乗は次のように再帰的に定義されます:

 n!=n×(n−1)!

これをPythonで実装すると以下のようになります。

def factorial_recursive(n):
    if n == 0 or n == 1:  # ベースケース
        return 1
    return n * factorial_recursive(n - 1)

この方法はシンプルですが、再帰が深くなるとスタックオーバーフローを起こす可能性があります。

ループを使った実装

再帰を使わず、ループを用いる方法もあります。

forループとwhileループの両方を使った例を示します。

forループ

def factorial_iterative(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

whileループ

def factorial_while(n):
    result = 1
    while n > 1:
        result *= n
        n -= 1
    return result

これらの方法は再帰を使わないため、スタックオーバーフローの心配がなく安定しています。

3. Python標準ライブラリを活用

math.factorialを使った実装

Pythonの標準ライブラリ math を使用すれば、簡単に階乗を計算できます。

import math

def factorial_math(n):
    return math.factorial(n)

最も簡単で効率的な方法の1つです。

functools.reduceを使った実装

functools.reduce を用いて、リストの要素を累積して掛け合わせることも可能です。

from functools import reduce

def factorial_reduce(n):
    return reduce(lambda x, y: x * y, range(1, n + 1), 1)

リスト内包表記とmath.prodを使った実装

Python 3.8以降では、math.prod を使用してリストやジェネレータの積を取ることができます。

from math import prod

def factorial_prod(n):
    return prod([i for i in range(1, n + 1)])

4. 効率化を図る手法

動的計画法による実装

動的計画法を利用すれば、以前に計算した結果を再利用して効率的に階乗を求められます。

def factorial_dynamic(n, memo={0: 1, 1: 1}):
    if n not in memo:
        memo[n] = n * factorial_dynamic(n - 1, memo)
    return memo[n]

メモ化を利用した実装

functools.lru_cache デコレータを使ってメモ化を自動化する方法もあります。

from functools import lru_cache

@lru_cache(None)
def factorial_memoized(n):
    if n == 0 or n == 1:
        return 1
    return n * factorial_memoized(n - 1)

クロージャを活用した実装

クロージャを使ってメモ化する例です。

def factorial_closure():
    memo = {0: 1, 1: 1}
    
    def compute(n):
        if n not in memo:
            memo[n] = n * compute(n - 1)
        return memo[n]
    
    return compute

fact = factorial_closure()

5. 高度な実装方法

ジェネレーターを使った階乗計算

ジェネレーターを使えば、途中経過を返すことができます。

def factorial_generator(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
        yield result

行列計算やベクトル化計算

NumPyを使ってベクトル化計算として階乗を求めることもできます。

import numpy as np

def factorial_numpy(n):
    return np.prod(np.arange(1, n + 1))

ライブラリを活用した高精度計算

SymPyによる実装

from sympy import factorial as sympy_factorial

def factorial_sympy(n):
    return sympy_factorial(n)

SciPyによる実装

from scipy.special import factorial as scipy_factorial

def factorial_scipy(n):
    return scipy_factorial(n, exact=True)

6. 特殊用途や応用的手法

文字列処理を利用した階乗の表現

数式を文字列として扱うことで、階乗の各要素を視覚的に表示できます。

def factorial_string(n):
    return " * ".join(str(i) for i in range(1, n + 1))

ビット操作で高速化

特殊なケースではビット操作を利用して計算を最適化することもできます。

def factorial_bits(n):
    if n == 0 or n == 1:
        return 1
    return (n << (n - 1)) * factorial_bits(n - 2)

7. 比較と用途別推奨

  • 効率性重視: 標準ライブラリの math.factorial
  • 大規模データ: NumPyやSciPyの利用
  • 近似が許容される場合: スターリングの近似
  • 高精度が必要な場合: SymPyやmpmath

8. まとめ

階乗はさまざまな方法で計算できますが、選択する手法は用途や要件に依存します。

本記事で紹介した方法を参考に、シチュエーションに合った最適な方法を選んでみてください。

階乗の計算はシンプルながらもプログラミングの奥深さを学ぶ絶好の題材です!

このサイトの記事一覧へは以下へアクセス!

統計検定 2級
統計学
ゴマフリーダムをフォローする

コメント

達人に学ぶDB設計 徹底指南書

最短コースでわかる ディープラーニングの数学

あたらしい機械学習の教科書 第3版

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

タイトルとURLをコピーしました