计算负IRR时触发ValueError: math domain error的通用解决方案求助
报错根因
这个ValueError: math domain error来自math.pow函数:fsolve是无约束求解器,迭代过程中会尝试i < -1的取值,此时1 + i < 0,对非整数次幂(比如你的场景里的0.99)求幂在实数域无定义,直接触发报错。你之前的临时方案本质是让迭代路径避开了i < -1的区间,没有从根本上解决问题,复杂场景下迭代还是会踩到非法取值。
彻底解决方案
核心做两处改进即可覆盖所有合法IRR求解场景,包括非整数时间节点、负IRR等复杂情况:
- 替换无约束的
fsolve为支持边界约束的求根工具,IRR的合理取值范围是i > -1(折现率不可能低于-100%),直接把求解下边界设为-0.999999(避免取到-1导致除零),从根源上避免迭代到非法区间 - 给NPV函数增加鲁棒性判断,就算迭代到非法取值也不会触发报错,直接返回超大残差引导求解器回到合法区间
修正后可运行代码
import math from scipy.optimize import root_scalar from functools import reduce dcfs = [0, 0.99] values = [-100, 50] def npvFromIrr(i): # 先做合法值判断,避免math.pow报错 if i <= -1: # 非法区间返回超大残差,引导求解器往i>-1的方向走 return 1e18 if i < -1 else 1e9 return reduce(lambda a, b: a + b, map(lambda x: x[1] / math.pow(1 + i, x[0]), zip(dcfs, values))) # 用带边界的brentq方法求解,指定IRR的合理范围是-0.999999到10(上限可根据业务调整,10对应1000%的IRR,覆盖绝大多数场景) sol = root_scalar(npvFromIrr, bracket=[-0.999999, 10], method='brentq') print(f"IRR计算结果:{sol.root:.2%}")
运行后输出结果约为-50.35%,符合业务预期。
内容的提问来源于stack exchange,提问作者user51725
相关产品推荐
相关产品推荐

