Python math.exp()とは?指数関数e^xを計算する方法を解説

Pythonのmath.exp()は、自然指数関数(e の x 乗)を計算する関数です。

eはネイピア数と呼ばれる約2.718の定数で、複利計算や確率分布、機械学習のシグモイド関数など幅広い場面で使われます。

この記事では、math.exp()の使い方と注意点を解説します。


math.exp()の基本的な使い方

import math

print(math.exp(0))
print(math.exp(1))
print(math.exp(2))
print(math.exp(-1))

実行結果:

1.0
2.718281828459045
7.38905609893065
0.36787944117144233

math.exp(1)はmath.eと同じ値です。

import math

print(math.exp(1) == math.e)

実行結果:

True

math.e ** x より精度が高い

同じ計算は**演算子でもできますが、結果がわずかに異なります。

import math

for x in [10, 50, 100]:
    a = math.exp(x)
    b = math.e ** x
    print(f"x={x:>3}  exp={a:.15e}  **={b:.15e}  同じ={a == b}")

実行結果(例):

x= 10  exp=2.202646579480672e+04  **=2.202646579480671e+04  同じ=False
x= 50  exp=5.184705528587072e+21  **=5.184705528587058e+21  同じ=False
x=100  exp=2.688117141816136e+43  **=2.688117141816118e+43  同じ=False

math.e ** xは、近似値であるeを繰り返し掛けるため誤差が蓄積します。

一方math.exp()は専用のアルゴリズムで直接計算するため、より正確です。指数計算にはmath.exp()を使ってください。


対数との関係

math.exp()とmath.log()は逆の関係にあります。

import math

x = 5.0

print(math.log(math.exp(x)))
print(math.exp(math.log(x)))

実行結果:

5.0
5.000000000000001

元の値に戻ります(わずかな誤差は浮動小数点数の宿命です)。


大きな値でオーバーフローする

import math

print(math.exp(700))
print(math.exp(710))

実行結果:

1.0142320547350045e+304
OverflowError: math range error

指数関数は急激に増大するため、引数が710程度を超えるとエラーになります。

興味深いことに、**演算子では無限大が返ります。

import math

print(math.e ** 710)

実行結果:

inf

同じ計算でも、エラーになるか無限大になるかが変わります。予期しない挙動を避けるため、大きな値を扱う可能性があるなら例外処理を入れましょう。

import math

def safe_exp(x):
    try:
        return math.exp(x)
    except OverflowError:
        return math.inf

print(safe_exp(1000))

逆に、極端に小さい値では0になります(アンダーフロー)。

import math

print(math.exp(-745))
print(math.exp(-746))

実行結果:

5e-324
0.0

実践例|シグモイド関数

機械学習で、値を0〜1の範囲に押し込めるために使われる関数です。

import math

def sigmoid(x):
    return 1 / (1 + math.exp(-x))

for x in [-5, -1, 0, 1, 5]:
    print(f"x={x:>3} → {sigmoid(x):.4f}")

実行結果:

x= -5 → 0.0067
x= -1 → 0.2689
x=  0 → 0.5000
x=  1 → 0.7311
x=  5 → 0.9933

どんな入力でも0〜1に収まるため、確率として扱えます。

ただし、この実装には落とし穴があります。

import math

def sigmoid(x):
    return 1 / (1 + math.exp(-x))

print(sigmoid(-1000))

実行結果:

OverflowError: math range error

exp(1000)を計算しようとして失敗します。実務では、符号で処理を分けた実装が使われます。

import math

def sigmoid(x):
    if x >= 0:
        return 1 / (1 + math.exp(-x))
    e = math.exp(x)
    return e / (1 + e)

print(sigmoid(-1000))
print(sigmoid(1000))
print(sigmoid(0))

実行結果:

0.0
1.0
0.5

どちらの分岐でもexp()の引数が0以下になるため、オーバーフローしません。


実践例|連続複利の計算

import math

def continuous_compound(principal, rate, years):
    return principal * math.exp(rate * years)

p = 1000000
r = 0.03

for y in [1, 5, 10, 30]:
    print(f"{y:>2}年後: {continuous_compound(p, r, y):>12,.0f}円")

実行結果:

 1年後:    1,030,455円
 5年後:    1,161,834円
10年後:    1,349,859円
30年後:    2,459,603円

年1回の複利と比べると、わずかに大きくなります。

p, r, y = 1000000, 0.03, 30

print(f"年1回複利: {p * (1 + r) ** y:>12,.0f}円")
print(f"連続複利 : {p * math.exp(r * y):>12,.0f}円")

実践例|放射性物質の減衰

import math

def decay(initial, half_life, time):
    k = math.log(2) / half_life
    return initial * math.exp(-k * time)

for t in [0, 30, 60, 90]:
    print(f"{t:>3}年後: {decay(100, 30, t):>6.2f}%")

実行結果:

  0年後: 100.00%
 30年後:  50.00%
 60年後:  25.00%
 90年後:  12.50%

半減期ごとに半分になっていく様子が再現できます。冷却や薬物の代謝など、「時間とともに一定割合で減る」現象はすべて同じ式で表せます。


関連する指数関数

関数 内容
math.exp(x) e の x 乗
math.expm1(x) exp(x) - 1を高精度に
math.exp2(x) 2 の x 乗(3.11以降)
math.pow(x, y) x の y 乗

expm1()は、xが極小のときに威力を発揮します。

import math

x = 1e-16

print(math.exp(x) - 1)
print(math.expm1(x))

実行結果:

0.0
1e-16

exp(x)がほぼ1になるため、1を引くと情報がすべて失われます。金利計算など小さな値を扱う場面ではexpm1()を使います。


math.exp()まとめ

ポイント 内容
構文 math.exp(x)
意味 e の x 乗
math.e ** xとの違い expのほうが正確
上限 約709(超えるとOverflowError)
逆関数 math.log()
小さい値 math.expm1()が高精度

シグモイド関数や減衰の計算では、オーバーフロー対策が実装の質を分けます。引数が大きくなる可能性を、必ず検討してください。


あわせて読みたい

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら