Pythonで`OverflowError: math range error`をmath.exp()と大きな数値で修正する方法

intermediate🐍 Python2026-05-08| Linux、macOS、Windows上のPython 3.x — float64の制限が適用されるすべてのプラットフォーム

Error Message

OverflowError: math range error
#python#math#overflow#float#numpy

シナリオ

数値計算の多いコードが正常に動いていたのに、突然動かなくなる。機械学習の損失関数、金融モデル、統計計算など。こんなエラーで処理が落ちます:

OverflowError: math range error

10回中9回は、こういったコードが原因です:

import math
math.exp(1000)
# OverflowError: math range error

あるいは、長い計算の3層奥深くに埋まっていて、途中の計算結果がこっそり巨大な値になっていることもあります。

なぜ起こるのか

PythonのmathモジュールはCのdouble型をラップしています。これは64ビット浮動小数点数で、上限は約1.8 × 10^308です。math.exp(709)は〜8.2×10^307を返し、範囲内に収まります。math.exp(710)は〜2.2×10^308になり、上限を超えます。Pythonはinfを黙って返すのではなく、OverflowError: math range errorを発生させます。

よくある原因:

  • x > ~709 の場合の math.exp(x)
  • 大きな入力値を使った math.cosh()math.sinh()
  • 大きな浮動小数点数を大きな冪乗にする場合
  • 反復アルゴリズムの途中の値(softmax、log-sum-expなど)
import math

math.exp(710)    # OverflowError
math.cosh(800)   # OverflowError
10.0 ** 309      # OverflowError

簡易修正:math.inf を使うか入力値をクランプする

クラッシュを止めたくて、infが許容できる結果なら、例外をキャッチしましょう:

import math

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

print(safe_exp(1000))  # inf

または、expに渡す前に入力値をクランプします:

import math

MAX_EXP = 709.78  # math.exp(709.78) は float64 の上限ギリギリ

def safe_exp(x):
    return math.exp(min(x, MAX_EXP))

print(safe_exp(1000))  # 8.218407461554972e+307

根本的な修正:numpy または decimal に切り替える

オプション1 — numpy(数値計算で最もよく使われる)

NumPyのnp.exp()は例外を発生させず、静かにinfを返します:

import numpy as np

np.exp(1000)   # inf  (エラーなし)
np.exp(710)    # inf
np.exp(700)    # 1.0142320547350045e+304

オーバーフローの警告も抑制したい場合は、errstateを使います:

import numpy as np

with np.errstate(over='ignore'):
    result = np.exp(np.array([700, 800, 1000]))
    print(result)  # [1.01423205e+304            inf            inf]

オプション2 — 任意精度演算には mpmath

infでは不十分で、実際の数値が必要な場合もあります。mpmathは任意の大きさの値を扱えます:

from mpmath import mp, exp

mp.dps = 50  # 小数点以下50桁の精度
result = exp(1000)
print(result)
# 5.0751411135066437985915844766989085095016671145491e+434

オプション3 — Pythonの標準 decimal モジュール

外部ライブラリは不要です。標準のdecimalモジュールでも対応できます:

from decimal import Decimal, getcontext

getcontext().prec = 50
result = Decimal(1000).exp()
print(result)
# 5.075141113506643798591584476698908509501667114549E+434

特殊ケース:Softmax と Log-Sum-Exp のオーバーフロー

softmaxをゼロから実装していませんか?このエラーが最も頻繁に起きる場面です:

import math

def softmax_naive(scores):
    exps = [math.exp(s) for s in scores]   # s > 709 の場合 OverflowError
    total = sum(exps)
    return [e / total for e in exps]

softmax_naive([1000, 2000, 3000])  # OverflowError

指数計算の前に最大値を引きましょう。数値安定性のためのよく知られたテクニックで、数学的には同じ結果になりますが、数値が扱いやすい範囲に収まります:

import math

def softmax_stable(scores):
    m = max(scores)
    exps = [math.exp(s - m) for s in scores]
    total = sum(exps)
    return [e / total for e in exps]

print(softmax_stable([1000, 2000, 3000]))
# [0.0, 0.0, 1.0]  — エラーなし

同じ考え方がlog-sum-expにも適用できます:

import math

def logsumexp(values):
    m = max(values)
    return m + math.log(sum(math.exp(v - m) for v in values))

print(logsumexp([1000, 2000, 3000]))  # 3000.0  — エラーなし

浮動小数点数の上限を調べる

お使いのシステムで正確な上限を知りたいですか?2行で全てわかります:

import sys
print(sys.float_info.max)   # 1.7976931348623157e+308
print(sys.float_info.min)   # 2.2250738585072014e-308

import math
print(math.log(sys.float_info.max))  # 709.782... — これが exp() の上限

動作確認

修正を適用した後、以下を実行して元のクラッシュが解消されたか確認しましょう:

import math
import numpy as np

# 修正前:
try:
    math.exp(1000)
except OverflowError as e:
    print(f"まだ壊れています: {e}")

# numpyで修正後:
result = np.exp(1000)
print(f"numpyの結果: {result}")    # numpy result: inf
print(f"infかどうか: {np.isinf(result)}")  # Is inf: True

# 安定版softmaxで修正後:
scores = [1000, 2000, 3000]
result = softmax_stable(scores)
print(f"Softmax OK: {result}")  # [0.0, 0.0, 1.0]

クイックリファレンス

  • math.exp() の安全な最大入力値:〜709.78
  • エラーの代わりに inf が欲しい場合numpy.exp()を使う
  • 正確な大きな値が必要な場合mpmath.exp()またはdecimal.Decimal.exp()を使う
  • Softmax/log-sum-exp のオーバーフロー:指数計算の前に最大値を引く — 必ず
  • numpyのオーバーフロー警告を抑制するnp.errstate(over='ignore')

Related Error Notes