使用scipy.fsolve求解x_Prime遇无解错误,但绘图显示存在解
scipy.optimize.fsolve求解方程失败的原因及解决办法
问题核心
你使用fsolve求解方程时触发无解错误,但绘图明确显示解存在,根源在于初始值选择不当,叠加函数特性导致迭代无法收敛到目标根。
关键数值分析
先计算方程中的固定参数值:
c_val=100时,f_NFW_val = math.log(1+100) - 100/(1+100) ≈ 3.625,因此1/f_NFW_val≈0.2759- 目标方程
eqn(x_Prime)=0等价于:0.2759*(math.log(1+100x)/x - 100/(1+100x)) = 3.0608 - 当
x=1时,右侧表达式的值≈1,远小于3.06,因此eqn(1)=3.06-1=2.06>0 - 根位于
x≈0.163处,此时右侧表达式恰好等于3.06,满足eqn(x)=0
为什么fsolve从x=1出发找不到根?
fsolve默认采用牛顿-拉夫逊法,该方法的收敛依赖两个条件:
- 初始猜测值需足够靠近根
- 函数在初始值附近的导数特性稳定
你的函数在x>0.163区间单调递减,从x=1到x=0.163,函数值从1升至3.06,但牛顿法从x=1出发时,由于初始值离根过远,迭代过程中可能因斜率变化导致步长不合理,甚至向x=0方向偏移(此时函数趋近于0,eqn(x)趋近于3.06,完全偏离目标根),最终触发收敛失败。
解决办法
方法1:调整初始值到根附近
直接将初始猜测值改为靠近根的数值(比如0.2),这是最可靠的方案:
import math import scipy.optimize as so c_val = 100 f_NFW_val = math.log(1+c_val)-c_val/(1+c_val) psi_prime = 3.0608421399604424 eqn = lambda x_Prime: psi_prime - 1/f_NFW_val * ( math.log(1+c_val*x_Prime)/x_Prime - c_val/(1+c_val*x_Prime) ) sol = so.fsolve(eqn, 0.2)[0] print(sol) # 输出≈0.1633804055843348,与绘图显示的根一致
方法2:使用区间搜索类方法
如果无法确定根的大致位置,可改用支持区间搜索的root_scalar(比如二分法),无需依赖初始值的精度:
import math from scipy.optimize import root_scalar c_val = 100 f_NFW_val = math.log(1+c_val)-c_val/(1+c_val) psi_prime = 3.0608421399604424 eqn = lambda x_Prime: psi_prime - 1/f_NFW_val * ( math.log(1+c_val*x_Prime)/x_Prime - c_val/(1+c_val*x_Prime) ) res = root_scalar(eqn, bracket=[0.1, 0.3], method='bisect') sol = res.root print(sol)
方法3:调整fsolve的迭代参数(不推荐)
若坚持使用初始值1,可通过增大迭代次数、调整容差尝试收敛,但效率较低且不稳定:
sol = so.fsolve(eqn, 1, maxfev=1000, xtol=1e-8)[0]
内容的提问来源于stack exchange,提问作者ellipse314
相关产品推荐
相关产品推荐

