c_cpp 牛顿法数值求解5次多项式的所有根。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 牛顿法数值求解5次多项式的所有根。相关的知识,希望对你有一定的参考价值。

#include<math.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>

typedef struct {int n_order; double *coeff; } ebao;

#define FP_OUTPUT_FORMAT "%.5lf"
#define SIGN_CHAR(x) (x >= 0 ? '+' : '-')

// allocate the poly and specify its degree
ebao* newpoly(int n) {
    ebao* poly = (ebao*) malloc(sizeof(ebao));
    poly->n_order = n;
    poly->coeff = (double*) malloc(sizeof(double) * (n + 1));
    return poly;
}

// deallocate the poly
void deletepoly(ebao* poly) {
    free(poly->coeff);
    poly->coeff = NULL;
    free(poly);
}

// make a copy the poly
ebao* copypoly(ebao* poly) {
    int n = poly->n_order;
    ebao* poly2 = newpoly(n);
    memcpy(poly2->coeff, poly->coeff, sizeof(double) * (n + 1));
    return poly2;
}

// read the coefficients (in ascending powers) from stdin
ebao* inputpoly(int deg) {
    ebao* poly = newpoly(deg);
    for (int i = 0; i <= deg; i++)
        scanf("%lf", poly->coeff + i);
    return poly;
}

// pretty-print the poly
void printpoly(ebao* poly) {
    int n = poly->n_order;
    if (n > 0)
        printf(FP_OUTPUT_FORMAT " x^%d", poly->coeff[n], n);
    for (int i = n - 1; i > 0; i--) {
        printf(" %c " FP_OUTPUT_FORMAT " x^%d",
            SIGN_CHAR(poly->coeff[i]), fabs(poly->coeff[i]), i);
    }
    printf(" %c " FP_OUTPUT_FORMAT, SIGN_CHAR(poly->coeff[0]), fabs(poly->coeff[0]));
}

// differentiate the poly
ebao* diffpoly(ebao* poly) {
    int n = poly->n_order;
    ebao* diff;
    if (poly->n_order == 0) {
        diff = newpoly(0);
        diff-> coeff[0] = 0;
        return diff;
    } else {
        diff = newpoly(n - 1);
        for (int i = 1; i <= n; i++) {
            diff->coeff[i - 1] = i * poly->coeff[i];
        }
    }
    return diff;
}

// substitute the x and yield the result
double evalpoly(double x, ebao* poly) {
    int n = poly->n_order;
    double val = poly->coeff[n];
    for (int i = n - 1; i >= 0; i--) {
        val = val * x + poly->coeff[i];
    }
    return val;
}

// divide the polynomial by (x - k); the remainder is dropped
ebao* divpoly(double k, ebao* poly) {
    int n = poly->n_order;
    ebao* quot = newpoly(n - 1);
    double val = 0;
    quot->coeff[n - 1] = poly->coeff[n];
    for (int i = n - 1; i > 0; i--) {
        quot->coeff[i - 1] = poly->coeff[i] + quot->coeff[i] * k;
    }
    return quot;
}

// get the zero of poly by Newton's method
double getzeropoly(double x, ebao* poly, double eps, int max_iter) {
    ebao* diff = diffpoly(poly);
    double xbest = x, mbest = INFINITY;
    while (max_iter) {
        double evalf = evalpoly(x, poly);
        double evald = evalpoly(x, diff);
        double evalm = evalf / evald;
        // printf("    x = %lf\tf = %lf\tf' = %lf\tf/f' = %lf\n", x, evalf, evald, evalm);

        x -= evalm;

        if (fabs(evalm) <= mbest) {
            mbest = fabs(evalm);
            xbest = x;
        }

        if (isnan(x) || mbest <= eps)
            break;
        --max_iter;
    }
    deletepoly(diff);
    if (isnan(x)) return NAN;
    return xbest;
}

void test() {
    // we manually pass predefined coefficients
    ebao* p5 = (ebao*) malloc(sizeof(ebao));
    p5->n_order = 5;
    double coeff[] = {1, 5, 10, 10, 5, 1};
    p5->coeff = coeff;
    ebao* dp5 = diffpoly(p5);
    ebao* p5dm1 = divpoly(-1, p5);

    free(p5);
    deletepoly(dp5);
    deletepoly(p5dm1);
}

int main() {
    printf("Enter coeffs: ");
    ebao* p5 = inputpoly(5);

    // test();

    printf("Input: ");
    printpoly(p5);
    puts("");

    printf("Now solving the roots\n");

    ebao* p5dup = copypoly(p5);

    for (int i = 0; i < 5; i++) {
        double sol;
        double try_init[] = {0, 1, -1, evalpoly(1, p5dup), evalpoly(-1, p5dup)};

        for (int i = 0; i < sizeof(try_init) / sizeof(double); i++) {
            printf("Trying %lf\n", try_init[i]);
            sol = getzeropoly(try_init[i], p5dup, 1e-7, 1000);
            if (!isnan(sol)) break;
        }
        if (isnan(sol)) break;

        printf("  ROOT #%d: " FP_OUTPUT_FORMAT "\n", i + 1, sol);

        ebao* fact = divpoly(sol, p5dup);
        if (fact->n_order == 0) {
            deletepoly(fact);
            break;
        }

        printf("  Factored form: (x %c " FP_OUTPUT_FORMAT ")", SIGN_CHAR(-sol), fabs(sol));
        printf("(");
        printpoly(fact);
        printf(")\n");

        deletepoly(p5dup);
        p5dup = fact;
    }

    if (p5dup->n_order == 1) {
        printf("ALL REAL ROOTS ARE SOLVED\n");
    } else {
        printf("CANNOT SOLVE ALL; MAY HAVE %d IMAGARY ROOT(S)\n", p5dup->n_order);
    }

    deletepoly(p5dup);
    deletepoly(p5);
}

以上是关于c_cpp 牛顿法数值求解5次多项式的所有根。的主要内容,如果未能解决你的问题,请参考以下文章

牛顿法、黄金分割法、二次插值法实验(最优化1)

牛顿法求解 matlab实现

matlab中牛顿法编程

什么是“牛顿法”或“牛顿迭代法”? 请简述过程及原理,有例子更好

牛顿法与拟牛顿法

牛顿法求解无约束最优化问题的方法