7-18 二分法求多项式单根

二分法求函数根的原理为:如果连续函数f(x)在区间[a,b]的两个端点取值异号,即f(a)f(b)<0,则它在这个区间内至少存在一个根r,即f(r)=0​。

二分法的步骤为:

  • 检查区间长度,如果小于给定阈值,则停止,输出区间中点(a+b)/2;否则
  • 如果f(a)f(b)<0则计算中点的值f((a+b)/2)
  • 如果f((a+b)/2)正好为0,则(a+b)/2就是要求的根;否则
  • 如果f((a+b)/2)f(a)同号,则说明根在区间[(a+b)/2,b],令a=(a+b)/2,重复循环;
  • 如果f((a+b)/2)f(b)同号,则说明根在区间[a,(a+b)/2],令b=(a+b)/2,重复循环。

本题目要求编写程序,计算给定3阶多项式f(x)=a3x3+a2x2+a1x+a0在给定区间[a,b]内的根。

输入格式

输入在第一行中顺序给出多项式的4个系数a3a2a1a0,在第2行中顺序给出区间端点ab。题目保证多项式在给定区间内存在唯一单根。

输出格式

在一行中输出该多项式在该区间内的根,精确到小数点后2位。

输入样例

3 -1 -3 1
-0.5 0.5

输出样例

0.33

分析与答案

看上去需要处理的系数比较多,也比较复杂,但是具体的步骤已经在题干中写得很清楚了,下面的程序将二分法的步骤和多项式的计算都写成一个单独的函数,从而让程序好看一点。

题目还包含一个隐藏条件。对于输入的多项式,有理数根可能是不存在的,而输出格式只要求精确到小数点后2位,意味着当这个区间的长度小于0.01时就可以将此时的区间中点输出为答案。

#include <stdio.h>
#define LENGTH 0.01

double func(double a3, double a2, double a1, double a0, double x);
double divide(double a3, double a2, double a1, double a0, double l,double r);
int main(){
    double a3,a2,a1,a0,l,r,res;
    scanf("%lf %lf %lf %lf",&a3,&a2,&a1,&a0);
    scanf("%lf %lf",&l,&r);
    res = divide(a3,a2,a1,a0,l,r);
    printf("%.2lf",res);
    return 0;
}
double divide(double a3, double a2, double a1, double a0, double l, double r){
    double mid;
    double func_mid,func_l,func_r;
    while(1){
        mid = (double) (l+r)/2;
        if(r-l < LENGTH)
            //区间小于指定值,退出循环
            return mid;
        //题目保证存在唯一单根,直接计算中点值
        func_mid = func(a3,a2,a1,a0,mid);
        if(func_mid == 0)
            //中点值为0,退出循环
            return mid;
        else{
            func_l = func(a3,a2,a1,a0,l);
            func_r = func(a3,a2,a1,a0,r);
            if(func_mid*func_l > 0){
                l = mid;
                continue;
            }
            else{
                r = mid;
                continue;
            }
        }
    }
}
double func(double a3, double a2, double a1, double a0, double x) {
    return (double) a3*x*x*x+a2*x*x+a1*x+a0;
}

7-18 测试点