Python运行含scipy/numpy代码报OverflowError: math range error如何解决
报错原因及解决方法
报错根因
这个错误由两个核心数值问题触发:
- 代码中大量使用
cm.exp()计算大参数复指数,当指数实部超过float64的上限(约709)时就会触发math range error,尤其是计算w(k0, s0, 200)时200倍的系数会大幅放大指数值 - 切比雪夫多项式
special.eval_chebyu()的输入绝对值大于1时,输出会指数级爆炸,进一步放大数值导致溢出
具体修复方案
替换cmath为numpy复数运算
numpy的复数运算溢出阈值更高,不会直接抛出错误,且支持向量化计算,替换所有cm.sqrt、cm.exp为np.sqrt、np.exp,同时删掉效率极低的np.vectorize包装,直接用循环实现批量计算。复指数数值裁剪
在计算指数前先检查指数的实部,超过float64安全范围就做截断,避免直接溢出:
def safe_complex_exp(z): max_real = 709.0 if z.real > max_real: z = complex(max_real, z.imag) elif z.real < -max_real: z = complex(-max_real, z.imag) return np.exp(z)
把代码中所有cm.exp替换为这个自定义的安全指数函数。
调整有限差分步长
scipy.misc.derivative默认步长1e-3和你的Y0量级不匹配,手动设置更小的步长dx=1e-6,减少数值误差导致的异常大值。切比雪夫计算稳定化
计算切比雪夫多项式前先对Omega矩阵做归一化,除以其谱范数避免迹过大,计算完成后再还原缩放系数。
修复后完整可运行代码
import numpy as np from scipy import special from scipy.misc import derivative def safe_complex_exp(z): max_real = 709.0 if z.real > max_real: z = complex(max_real, z.imag) elif z.real < -max_real: z = complex(-max_real, z.imag) return np.exp(z) def T(X, Y): s0 = np.sign(X) s1 = np.sign(X - 15) s3 = np.sign(X + 15) k0 = np.sqrt( X**2 -(10*Y)**2 )/10 k1 = np.sqrt( ((X - 15)**2) - (10*Y)**2 )/10 k3 = np.sqrt( ((X + 15)**2) - (10*Y)**2 )/10 def z(k): return complex(k, -Y)/np.sqrt(k**2 + Y**2) def w(k, s, x): exp1 = safe_complex_exp(complex(0, 1)*k*x) exp2 = safe_complex_exp(-complex(0, 1)*k*x) exp3 = safe_complex_exp(-complex(0, 1)*z(k)*x) zk = z(k) return np.array([[exp1, exp2], [s*zk*exp1, -s*exp3/zk]]) I15 = np.linalg.inv(w(k1, s1, 5)) I05 = np.linalg.inv(w(k0, s0, 5)) I310 = np.linalg.inv(w(k3, s3, 10)) Omega = w(k1, s1, 0).dot(I15).dot(w(k0, s0, 5)).dot(I05).dot(w(k3, s3, 5)).dot(I310) # 切比雪夫计算稳定化 norm = np.linalg.norm(Omega, ord=2) Omega_norm = Omega / norm Omegan = special.eval_chebyu(19, np.trace(Omega_norm)/2)*Omega_norm - special.eval_chebyu(18, np.trace(Omega_norm)/2)*np.identity(2) Omegan = Omegan * (norm ** 19) I00 = np.linalg.inv(w(k0, s0, 0)) tt = I00.dot(Omegan).dot(w(k0, s0, 200)) t = 1/tt[0][0] return np.log(t) def V(X): Y0 = X*np.sin(np.deg2rad(2))/10 result = derivative(func=T, x0=Y0, args=(X,), dx=1e-6)*X/(20*np.pi) return -result.imag X = np.linspace(0.01, 10, 1000) VX = np.array([V(x) for x in X])
内容的提问来源于stack exchange,提问作者ABDOU
相关产品推荐
相关产品推荐

