二分法求根精度异常及mpmath库mp.mpf使用位置咨询
嗨,我来帮你拆解下问题:首先你的代码里有个致命的逻辑小错误,这是导致结果完全偏离预期的核心原因,然后再给你讲mpmath库该怎么用到代码里~
1. 先解决最关键的bug:二分法中点计算错误
你看cut函数里的中点判断,写成了f((b-a)/2)——这完全不对啊!(b-a)/2是区间的长度的一半,而不是区间[a,b]的中点!正确的中点应该是(a + b)/2,这个错误直接让你的区间更新逻辑全乱了,比如你传入6和9,正确的根是√17≈4.123,但你的代码却在6附近打转,就是因为中点找错了。
修正后的cut函数应该是这样的:
def cut(a,b,f): mid = (a + b) / 2 # 这里改成正确的中点计算! if f(a) < 0 : if f(mid) < 0: return [mid, b] else : return [a, mid] else : if f(mid) > 0 : return [mid, b] else : return [a, mid]
2. mpmath库的正确使用位置(解决高精度需求)
你说的没错,当需要10^-10级别的精度时,Python默认的float双精度虽然理论上够,但如果要避免累积误差或者需要更高精度,用mpmath的高精度浮点数mp.mpf是个好选择。具体要在这些地方用:
(1)初始化区间时转高精度
在conv_dichotomy函数里,把初始的上下界转成mp.mpf类型,这样后续所有计算都会基于高精度数值:
def conv_dichotomy(a, b, g, k): lowerBound = mp.mpf(a) # 把初始值转成高精度浮点数 higherBound = mp.mpf(b) interval = [] count = 0 # 循环的精度阈值也用mpmath生成高精度值 tolerance = mp.power(10, -k) while higherBound - lowerBound > tolerance: interval = cut(lowerBound, higherBound, g) lowerBound, higherBound = interval # 补全你截断的区间赋值逻辑 count += 1 # 返回迭代次数和最终的高精度区间 return (count, [lowerBound, higherBound])
(2)函数计算自动适配高精度
你的g(x)函数不需要额外修改,当传入的x是mp.mpf类型时,pow(x,2)-17的结果会自动变成高精度数值,完美适配:
def g(x): return pow(x, 2) - 17
(3)全局精度配置(可选)
你已经设置了mp.mp.dps=10,这个配置是生效的——它表示全局高精度浮点数保留10位有效小数,刚好匹配你10^-k的精度要求(当k=10时)。
3. 关于你得到的0.0精度问题
之前因为中点计算错误,你的区间更新逻辑完全混乱,导致循环结束时的区间差可能因为float精度截断或者逻辑错误变成0.0。修正中点计算后,再配合mpmath的高精度,就能得到正确的精度结果了。
比如你调用conv_dichotomy(6, 9, g, 10),修正后会得到接近√17的区间,迭代次数依然会是35次左右,但区间会是正确的[4.123105625617661, ...]范围。
备注:内容来源于stack exchange,提问作者yassine_deux_s

