一元三次方程,若已知必有一正实根,求根(若有多个根只需求任意一个)
二分解法
数值法,用二分去逼近解的区间,高中数学流程图那章有类似的题。
对于区间[a,b]
,若满足下式,则区间内必有一根。
对于必有一根的区间[a,b]
,可以如下所示用二分去缩小区间。停止条件为解的误差(即区间长度)小于某值或者解代入函数十分接近0。
核心代码如下:
ans = 0
while (r-l) > 10**(-7):
mid = (l+r)/2
fmid = f(mid, a, b, c)
if fmid == 0:
ans = mid
break
elif fmid*fl < 0:
r = mid
else:
l = mid
ans = l if ans == 0 else ans
最初的右边界怎么找
如果系数a,b,c有一定范围,那就可以大致求一个右边界出来,例如若a,b,c都为正整数,则右边界为c。对于更一般的情况,可以用逆向二分去找到一个初始的右边界。
即,若不满足条件则 r <- r*2,直到满足边界值异号。
l, r =0, 1
fl = -c
fr = f(r, a, b, c)
while fr*fl > 0:
r *= 2
fr = f(r, a, b, c)
完整代码
n = int(input())
def f(x, a, b, c):
return x**3+a*(x**2)+b*x-c
for _ in range(n):
ans = 0
a, b, c = map(int, input().split())
l, r = 0, 1
fl = -c
fr = f(r, a, b, c)
while fr*fl > 0:
r *= 2
fr = f(r, a, b, c)
if fr == 0:
ans = r
print(round(float(ans), 8))
continue
while (r-l) > 10**(-7):
mid = (l+r)/2
fmid = f(mid, a, b, c)
if fmid == 0:
ans = mid
break
elif fmid*fl < 0:
r = mid
else:
l = mid
ans = l if ans == 0 else ans
print(round(float(ans), 8))