问题六十二:怎么求一元十次方程在区间内的所有不相等的实根

32 篇文章 7 订阅

在“问题五十九”中解一元六次方程时,就有提到,对应的方法可以推广到更高次多项式方程。

现在,由于要用ray tracing画sphere sweeping图形,若对应的曲线是3次b-spline曲线,则需要解一元十次方程(10=2*(2*3-1))。

我们接下来就看看一元十次方程怎么解?

 

62.1 理论分析

参考“问题五十九:怎么求一元六次方程在区间内的所有不相等的实根(1)”

http://blog.csdn.net/libing_zeng/article/details/54605140

 

参考“问题五十九:怎么求一元六次方程在区间内的所有不相等的实根(2)”

http://blog.csdn.net/libing_zeng/article/details/54606500

 

参考“问题五十九:怎么求一元六次方程在区间内的所有不相等的实根(3)——修正一个问题”

http://blog.csdn.net/libing_zeng/article/details/54619148

 

一元六次方程和一元十次方程的求解过程有什么不同的地方呢?简单来说,只要将其中出现“六”的地方改成“十”就可以了。主要要改的地方在判断方程在区间内不等实根的总个数的过程中;牛顿迭代在子区间找根的过程几乎完全一样。

 

62.2 看C++代码实现

代码也几乎和求解一元六次方程时的一样,所以接下来不会有特别注释。

 

----------------------------------------------vec3.h ------------------------------------------

vec3.h

bool roots_num_equation_10th(float ee10[11], double a, double b, int &num);
bool roots_equation_10th(float ee10[11], float a, float b, float tol, float (&roots)[11]);

----------------------------------------------vec3.cpp ------------------------------------------

vec3.cpp

bool roots_num_equation_10th(float ee10[11], double a, double b, int &num) {
        double temp1, temp2;
        double ee1111[11][11] = {0.0};
        double fun_a[11] = {0.0};
        double fun_b[11] = {0.0};
        int change_num_a = 0;
        int change_num_b = 0;

        for (int i=0; i<10; i++) {
        //determine f0, f1
            ee1111[0][i] = ee10[i];
            ee1111[1][i] = (10-i)*ee10[i];
        }
        ee1111[0][10] = ee10[10];

        for (int i=2; i<10; i++) {
        //determine f2, f3, f4, f5, f6, f7, f8, f9
            temp1 = ee1111[i-2][0] / ee1111[i-1][0];
            temp2 = (ee1111[i-2][1] - temp1*ee1111[i-1][1]) / ee1111[i-1][0];
            for (int j=0; j<(10-i); j++) {
                ee1111[i][j] = temp1*ee1111[i-1][j+2] + temp2*ee1111[i-1][j+1] - ee1111[i-2][j+2];
                if (fabs(ee1111[i][j])<1e-5) {
                    ee1111[i][j] = 0.0;
                }
            }
            ee1111[i][10-i] = temp2*ee1111[i-1][10-i+1] - ee1111[i-2][10-i+2];
            if (fabs(ee1111[i][10-i])<1e-5) {
                ee1111[i][10-i] = 0.0;
            }

            if ((ee1111[i][0] == 0.0) && (ee1111[i][1] == 0.0) && (ee1111[i][2] == 0.0) &&
                (ee1111[i][3] == 0.0) && (ee1111[i][4] == 0.0) && (ee1111[i][5] == 0.0) &&
                (ee1111[i][6] == 0.0) && (ee1111[i][7] == 0.0) && (ee1111[i][8] == 0.0) &&
                (ee1111[i][9] == 0.0) && (ee1111[i][10] == 0.0)) {
                break;
            }
        }
        if (fabs(ee1111[9][0])>1e-5) {
        //determine f10
            temp1 = ee1111[8][0] / ee1111[9][0];
            temp2 = (ee1111[8][1] - temp1*ee1111[9][1]) / ee1111[9][0];
            ee1111[10][0] = temp2*ee1111[9][1] - ee1111[8][2];
            if (fabs(ee1111[10][0])<1e-5) {
                ee1111[10][0] = 0.0;
            }
        }
        else {
            ee1111[10][0] = 0.0;
        }

        for (int j=0; j<11; j++) {
            fun_a[0] = fun_a[0] + ee1111[0][j]*pow(a, (6-j));
            fun_b[0] = fun_b[0] + ee1111[0][j]*pow(b, (6-j));
        }
        for (int i=1; i<11; i++) {
            for (int j=0; j<(11-i); j++) {
                fun_a[i] = fun_a[i] + ee1111[i][j]*pow(a, ((6-i)-j));
                fun_b[i] = fun_b[i] + ee1111[i][j]*pow(b, ((6-i)-j));
            }
            if ((fun_a[i]*fun_a[i-1]) < 0) {
                change_num_a ++;
            }
            if ((fun_b[i]*fun_b[i-1]) < 0) {
                change_num_b ++;
            }
        }
        num = abs(change_num_a - change_num_b);
        return true;
}

bool get_equation_10th_function_and_derivative(float ee10[11], double xxx, double& fnc, double& drv) {
    /*determine function value and derivative value at xxx*/
        fnc = 0.0;
        drv = 0.0;
        for (int i=0; i<11; i++) {
            fnc = fnc + ee10[i]*pow(xxx, (10-i));
            if (i<10) {
                drv = drv + (10-i)*ee10[i]*pow(xxx, (9-i));
            }
        }
        return true;
}

bool get_root_by_newton_iteration_for_equation_10th(float ee10[11], double x0[2], float tol, double (&root)[2]) {
    /*find the single root in the interval [x0[0], x0[1]] by newton iteration */
        double t_k, t_k1, ft_k, ft_d_k;
        int get = 0;

        for (int i=0; i<2; i++) {
            t_k = x0[i];
            for (int k=0; k<20; k++) {
                if (!(isnan(t_k))) {
                    get_equation_10th_function_and_derivative(ee10, t_k, ft_k, ft_d_k);
                    if ((ft_d_k != 0) && !(isnan(ft_k)) && !(isnan(ft_d_k))) {
                        t_k1 = t_k - ft_k/ft_d_k;
                        if (((fabs(t_k1)>=1e-2)&&(fabs((t_k1 - t_k)/t_k1) < tol)) ||
                            ((fabs(t_k1)<1e-2)&&(fabs((t_k1 - t_k)) < tol))) {
                            if ((t_k1 > x0[0]) && (t_k1<=x0[1])) {
                                root[1] = (fabs(t_k1)<(tol*10))? 0.0:t_k1;
                                root[0] = 1.0;
                                get ++;
                            }
                            else {
                                x0[1] = (x0[0] + x0[1])/2;
                            }
                            break;
                        }
                        else {
                            t_k = t_k1;
                        }
                    }
                    else {
                        break;
                    }
                }
                else {
                    break;
                }
            }
            if (get == 1) {
                break;
            }
        }
        root[0] = double(get);
        return true;
}

bool roots_equation_10th(float ee10[11], float a, float b, float tol, float (&roots)[11]) {
        double root[2], xxx0[2], temp;
        double left = a;
        double right = b;
        int total_num, interval_num;
        int offset = 0;
        roots[0] = 0.0;
        roots_num_equation_10th(ee10, double(a), double(b), total_num);
        if (total_num == 0) {
            return true;
        }
        else {
            interval_num = total_num;
            for (int i=1; i<(total_num+1+offset); i++) {
                while(interval_num != 1) {
                    if (left > right) {
                        temp = left;
                        left = right;
                        right = temp;
                    }
                    right = (left + right)/2;

                    roots_num_equation_10th(ee10, left, right, interval_num);
                    if (interval_num == 0) {
                        left = right;
                        right = b;
                        if (left == right) {
                        /*s2: handle the situation that both left and right value reach the right end of the whole interval*/
                            break;
                        }
                    }
                    else if (fabs(left-right)<tol) {
                    /*s1: left and right value are are so close that their values even don't change under sub-dividing*/
                        break;
                    }
                }
                if (interval_num == 0) {
                /*s2: handle the situation that both left and right value reach the right end of the whole interval*/
                    break;
                }
                xxx0[0] = left;
                xxx0[1] = right;
                get_root_by_newton_iteration_for_equation_10th(ee10, xxx0, tol, root);
                if (root[0] != 0.0) {
                    roots[0] = roots[0] + 1.0;
                    roots[int(roots[0])] = root[1];
                    left = right;
                    right = b;
                }
                else if ((root[0] == 0.0)&&(fabs(left-right)<tol)&&(interval_num>=1)) {
                /*s1: left and right value are are so close that their values even don't change under sub-dividing,
                the interval_num may be more than one, so we modify "interval_num==1" to "interval_num>=1"*/
                    roots[0] = roots[0] + 1.0;
                    roots[int(roots[0])] = left;
                    left = right;
                    right = b;
                }
                else {
                    offset ++;
                    right = (left + right)/2;
                }

                roots_num_equation_10th(ee10, left, right, interval_num);
            }
        }
        return true;
}

----------------------------------------------main.cpp ------------------------------------------

main.cpp

    int main(){
//equation of 10th degree
        float ee10[11] = {1.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};//x^10------------1
        float a = -10;
        float b =  10;
        int num;
        float tol = 1e-6;
        float roots[11];
        roots_num_equation_10th(ee10, a, b, num);
        std::cout << "the coefficients of the equation of 10th degree are:" << endl;
        for (int i=0; i<11; i++) {
            std::cout << ee10[i] << "  ";
        }
        std::cout << endl;
        std::cout << "the corresponding equation is:" << endl;
        std::cout << " x^10=0" << endl;
        std::cout << endl;
        std::cout << "the number of roots of this equation in the interval [" << a << ", " << b << "] is: " << num << endl;

        if (num > 0) {
            roots_equation_10th(ee10, a, b, tol, roots);
            std::cout << "the roots are: ";
            for (int j=1; j<(num+1); j++){
                std::cout << roots[j] << " ";
            }
            std::cout << endl;
        }
    }


测试结果如下:


接下来再测试一下如下方程:

//        float ee10[11] = {1.0, -1.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};//x^9*(x-1)------------2
//        float ee10[11] = {1.0,  0.0, -1.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};//x^8*(x+1)*(x-1)------------3
//        float ee10[11] = {1.0,  0.0, -5.0,  0.0,  4.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};//x^6*(x+1)*(x-1)*(x+2)*(x-2)------------5
//        float ee10[11] = {1.0,  0.0, -14.0,  0.0,  49.0,  0.0,  -36.0,  0.0,  0.0,  0.0,  0.0};//x^4*(x+1)*(x-1)*(x+2)*(x-2)*(x+3)*(x-3)------------7
//        float ee10[11] = {1.0,  0.0, -30.0,  0.0,  273.0,  0.0,  -820.0,  0.0,  576.0,  0.0,  0.0};//x^2*(x+1)*(x-1)*(x+2)*(x-2)*(x+3)*(x-3)*(x+4)*(x-4)------------9
//        float ee10[11] = {1.0, -5.0, -30.0,  150.0,  273.0, -1365.0,  -820.0, 4100.0,  576.0, -2880.0,  0.0};//x*(x+1)*(x-1)*(x+2)*(x-2)*(x+3)*(x-3)*(x+4)*(x-4)*(x-5)------------10

测试结果依次如下:












 

截至当前只测试了这几个方程,后续会将这个程序用于sphere sphere的ray tracing图形。如果遇到问题需要修正该程序的话,后续再来补充。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值