Sửa lỗi 'OverflowError: math range error' trong Python với math.exp() và số lớn

intermediate🐍 Python2026-05-08| Python 3.x trên Linux, macOS, Windows — mọi nền tảng áp dụng giới hạn float64

Error Message

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

Tình huống

Code tính toán nặng của bạn đang chạy ổn — cho đến khi nó không ổn nữa. Một hàm loss trong machine learning, một mô hình tài chính, một phép tính thống kê. Rồi đột nhiên nổ ra với:

OverflowError: math range error

Chín trên mười trường hợp, nguyên nhân bắt nguồn từ đại loại như thế này:

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

Hoặc nó bị chôn vùi ba tầng sâu trong một phép tính dài hơn, nơi một kết quả trung gian nào đó âm thầm phình to khổng lồ.

Tại sao điều này xảy ra

Module math của Python bọc kiểu double của C — một số thực 64-bit với giới hạn trên xấp xỉ 1.8 × 10^308. math.exp(709) trả về ~8.2×10^307, vẫn nằm trong giới hạn. math.exp(710) sẽ trả về ~2.2×10^308 — và con số đó vượt ngưỡng. Thay vì trả về inf âm thầm, Python ném ra OverflowError: math range error.

Các thủ phạm thường gặp:

  • math.exp(x) khi x > ~709
  • math.cosh(), math.sinh() với đầu vào quá lớn
  • Lũy thừa một số thực lớn lên một số mũ lớn
  • Các giá trị trung gian trong thuật toán lặp (ví dụ: softmax, log-sum-exp)
import math

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

Sửa nhanh: Dùng math.inf hoặc giới hạn đầu vào

Muốn code không crash nữa và inf là kết quả chấp nhận được? Bắt ngoại lệ:

import math

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

print(safe_exp(1000))  # inf

Hoặc giới hạn đầu vào trước khi nó chạm đến exp:

import math

MAX_EXP = 709.78  # math.exp(709.78) vừa dưới giới hạn float64

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

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

Sửa triệt để: Chuyển sang numpy hoặc decimal

Lựa chọn 1 — numpy (phổ biến nhất cho tính toán số)

np.exp() của NumPy trả về inf âm thầm, không ném ngoại lệ:

import numpy as np

np.exp(1000)   # inf  (không có lỗi)
np.exp(710)    # inf
np.exp(700)    # 1.0142320547350045e+304

Muốn tắt luôn cả cảnh báo overflow? Dùng 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]

Lựa chọn 2 — mpmath để có độ chính xác tùy ý

Đôi khi inf chưa đủ — bạn cần con số thực sự. mpmath xử lý được các giá trị lớn tùy ý:

from mpmath import mp, exp

mp.dps = 50  # 50 chữ số thập phân độ chính xác
result = exp(1000)
print(result)
# 5.0751411135066437985915844766989085095016671145491e+434

Lựa chọn 3 — module decimal có sẵn trong Python

Không cần thư viện ngoài. Module decimal chuẩn cũng xử lý được:

from decimal import Decimal, getcontext

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

Trường hợp đặc biệt: Tràn số trong Softmax và Log-Sum-Exp

Tự cài softmax từ đầu? Đây là nơi lỗi hay cắn nhất:

import math

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

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

Trừ giá trị lớn nhất trước khi tính hàm mũ. Đây là thủ thuật ổn định số học nổi tiếng — kết quả toán học hoàn toàn tương đương, nhưng các con số vẫn trong tầm kiểm soát:

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]  — không có lỗi

Tương tự với 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  — không có lỗi

Kiểm tra giới hạn số thực

Tò mò giới hạn trên nằm chính xác ở đâu trên hệ thống của bạn? Hai dòng này cho bạn biết tất cả:

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... — đây là giới hạn trên của exp()

Kiểm tra lại

Chạy đoạn này sau khi áp dụng cách sửa để xác nhận lỗi gốc đã biến mất:

import math
import numpy as np

# Trước khi sửa:
try:
    math.exp(1000)
except OverflowError as e:
    print(f"Vẫn còn lỗi: {e}")

# Sau khi sửa bằng numpy:
result = np.exp(1000)
print(f"Kết quả numpy: {result}")    # numpy result: inf
print(f"Là inf: {np.isinf(result)}")  # Is inf: True

# Sau khi sửa bằng softmax ổn định:
scores = [1000, 2000, 3000]
result = softmax_stable(scores)
print(f"Softmax OK: {result}")  # [0.0, 0.0, 1.0]

Tham khảo nhanh

  • Đầu vào an toàn tối đa cho math.exp(): ~709.78
  • Muốn trả về inf thay vì lỗi: dùng numpy.exp()
  • Cần giá trị lớn chính xác: dùng mpmath.exp() hoặc decimal.Decimal.exp()
  • Tràn số trong softmax/log-sum-exp: luôn trừ giá trị lớn nhất trước khi tính exp
  • Tắt cảnh báo overflow của numpy: np.errstate(over='ignore')

Related Error Notes