Skip to the content.

← 目次← 前: 02次: 04 →

03. ループと数式

テーマ: 複利計算・実効年利・「72の法則」の検証

学習点: while ループ, math モジュール, 関数の既定引数, 反復計算と閉形式の比較

依存: 標準ライブラリのみ / 難易度: 基礎

実行方法

uv run 03_compound_interest.py

スクリプト冒頭の PEP 723 メタデータ(# /// script)により、必要なライブラリは uv が自動的に仮想環境へ導入します。事前の pip install は不要です。

解説

何をするプログラムか

複利は「利息が利息を生む」仕組みで、金融の最も基本的な計算です。このスクリプトは、元本 100 万円を年利 3% で 20 年運用したときの将来価値を、(1) 公式(閉形式)、(2) 毎年利息を積み上げるループ、(3) 連続複利の 3 通りで計算して突き合わせます。

続いて、名目年利 5% のまま複利の回数を年 1 回 → 半年 → 四半期 → 毎月 → 毎日と増やすと実効年利がどこまで上がるかを観察し、最後に「元本が 2 倍になる年数 ≒ 72 ÷ 金利(%)」という有名な暗算法「72 の法則」の精度を、対数を使った厳密解と比較して検証します。

コードの読みどころ

理論的背景

年 n 回複利では、1 年間で元本は (1 + r/n)^n 倍になるため、実効年利は (1+r/n)^n − 1 です。n を無限に大きくした極限が連続複利で、微積分で学ぶ極限公式 lim (1+r/n)^n = e^r により実効年利は e^r − 1 に収束します。つまり複利回数をいくら増やしても実効年利には上限があります。

元本が 2 倍になる年数は (1+r)^t = 2 を解いた t = ln2 / ln(1+r) です。r が小さいとき ln(1+r) ≒ r なので t ≒ 0.693/r、つまり「69.3 ÷ 金利(%)」ですが、実用では約数が多く暗算しやすい 72 が使われます。72 を使うことで、r がある程度大きい領域でも誤差が相殺されます。

実行結果の見方

最初のブロックでは閉形式とループがともに 1,806,111 円で一致し、連続複利は 1,822,119 円とわずかに大きくなります。複利頻度の表では、実効年利が 5.000% → 5.127% へと増えるものの、毎日複利(5.12675%)と連続複利(5.12711%)はほぼ同じで、「上限」への収束が数値で見えます。

72 の法則の表では、誤差は年利 1% で +2.34 年ある一方、8% では −0.01 年とほぼ完璧です。末尾の注記どおり、年利 6〜10% 付近で最も精度が高い近似であることが確認できます。

ソースコード

# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""03: ループと数式 -------------------------------------------------------
テーマ: 複利計算・実効年利・「72の法則」の検証
学習点: while ループ, math モジュール, 関数の既定引数, 反復計算と閉形式の比較
根拠: 年n回複利の実効年利は (1+r/n)^n - 1、連続複利では e^r - 1 に収束する。
      「72の法則」は ln2/ln(1+r) の近似(r が小さいとき ln(1+r)≒r より 0.693/r)。
"""
import math


def future_value(pv: float, rate: float, years: int, n: int = 1) -> float:
    """年利rate・年n回複利でyears年後の将来価値(閉形式)。"""
    return pv * (1 + rate / n) ** (n * years)


def future_value_loop(pv: float, rate: float, years: int) -> float:
    """同じ計算をループで(1年複利)。閉形式と一致することを確認する。"""
    v = pv
    for _ in range(years):
        v *= 1 + rate
    return v


def years_to_double(rate: float) -> float:
    """元本が2倍になる年数(厳密解)。"""
    return math.log(2) / math.log(1 + rate)


def main() -> None:
    pv, rate, years = 1_000_000, 0.03, 20
    print(f"元本 {pv:,}円 / 年利 {rate:.1%} / {years}年")
    print(f"  閉形式  : {future_value(pv, rate, years):>14,.0f} 円")
    print(f"  ループ  : {future_value_loop(pv, rate, years):>14,.0f} 円")
    print(f"  連続複利: {pv * math.exp(rate * years):>14,.0f} 円")

    print("\n[複利頻度と実効年利] 名目年利 5%")
    r = 0.05
    for n, label in [(1, "年1回"), (2, "半年"), (4, "四半期"),
                     (12, "毎月"), (365, "毎日")]:
        print(f"  {label:<6} 実効年利 {(1 + r / n) ** n - 1:.6%}")
    print(f"  連続複利 実効年利 {math.exp(r) - 1:.6%}  <- 上限")

    print("\n[72の法則の精度検証]")
    print(f"  {'年利':>6}{'厳密解':>10}{'72の法則':>10}{'誤差':>9}")
    for r in [0.01, 0.02, 0.03, 0.05, 0.08, 0.12, 0.20]:
        exact, approx = years_to_double(r), 72 / (r * 100)
        print(f"  {r:>6.0%}{exact:>10.2f}{approx:>10.2f}{approx - exact:>9.2f}")
    print("  ※ 年利6-10%付近で近似精度が最も高い。")


if __name__ == "__main__":
    main()

実行結果

元本 1,000,000円 / 年利 3.0% / 20年
  閉形式  :      1,806,111 円
  ループ  :      1,806,111 円
  連続複利:      1,822,119 円

[複利頻度と実効年利] 名目年利 5%
  年1回    実効年利 5.000000%
  半年     実効年利 5.062500%
  四半期    実効年利 5.094534%
  毎月     実効年利 5.116190%
  毎日     実効年利 5.126750%
  連続複利 実効年利 5.127110%  <- 上限

[72の法則の精度検証]
      年利       厳密解     72の法則       誤差
      1%     69.66     72.00     2.34
      2%     35.00     36.00     1.00
      3%     23.45     24.00     0.55
      5%     14.21     14.40     0.19
      8%      9.01      9.00    -0.01
     12%      6.12      6.00    -0.12
     20%      3.80      3.60    -0.20
  ※ 年利6-10%付近で近似精度が最も高い。

← 目次← 前: 02次: 04 →