• 非线性方程求根(数值分析)C++


    1. 二分搜索

      经典算法了,数组的二分检索和它相似,不过数组的二分查找要求数组有序,反映在非线性方程求根就是函数单调。不过二分搜索不要求函数单调。因为随着区间长度减半,如果能够求出满足精度的近似解,不断减半的区间内,函数终会单调。

      需要注意的还有:如果循环结束条件为所求近似根满足精度,如果搜索区间内没有根,那么很有可能无法结束循环,并且设计逻辑比较复杂,根据区间长度是否小于一定长度决定是否结束循环比较合理。

      params: 区间端点,要求的精度

      return: 近似解

    自己定义一个函数,例如:double fun1(double x) {return x * x * x - x - 1;}

    int iterCount = 0;
    double binarySearch(double left, double right, double precision) {
        double mid = (left + right) / 2;
        iterCount++;
        printf("
    二分迭代次数为: %d
    ", iterCount);
        double result = fun1(mid);
        if (right-left < precision) {
            return mid;
        }
        else if (result * fun1(left) < 0) {
            return binarySearch(left, mid, precision);
        }
        else if (result * fun1(right) < 0) {
            return binarySearch(mid, right, precision);
        }
        else {
            return binarySearch(mid, right, precision);
        }
        return 0;
    }

    2. 简单迭代法

      通过移项,使方程等号左侧为x。需要注意的是,迭代方程要保证收敛,如何移项就是考技巧了。需要注意的是,迭代法不需要指定区间,它是自适应的搜索。不过需要指定初始解,这也是启发式算法的特征。

      以下大体框架也适用于牛顿迭代法,割线迭代法。程序稍加修改就成了。

      params: 初始解,要求的精度

      return: 近似解

    自己定义一个迭代函数,比如:double fun2(double){ return 0.25*(x * x * x * x * x - 2);}

    double simpleIterator(double x0, double err) {
        double f0 = fun2(x0);
        double f1 = fun2(f0);
        double res = f1 - f0;
        iterCount++;
        if (res < 0) {
            res = -res;
        }
        while (true) {
            f0 = f1;
            f1 = fun2(f0);
            double res = f1 - f0;
            if (res < 0) {
                res = -res;
            }
            if (res < err)
                break;
        }
        return f1;
    }

    3. Newton迭代法:基于如果$f(x)=0, f(x)$是线性函数的话,那么其求根是容易的。Newton法本质上就是一种线性化方法,基本思想是将非线性方程$f(x)=0$逐步归结为某种下逆行方程来求解。(《数值分析》孙家广)。$f(x)=f(x_k)+f'(x_k)(x-x_k)+frac{(x-x_k)^2}{2}f''(xi)$,通过移项和近似转化为迭代方程$x_{k+1} = x_k - frac{f(x_k)}{f'(x_k)}$。

    程序如下

    double func(double x) {
        return x * x * x - x - 1;
    }
    
    double funcDiff(double x) {
        return 3 * x * x - 1;
    }
    
    double newtonIter(double x0, double MAX_ITER) {
        double preX;
        double x;
    
        preX = x0;
        x = preX - func(preX) / funcDiff(preX);
        int itercount = 0;
        while (itercount < MAX_ITER) {
            preX = x;
            x = preX - func(preX) / funcDiff(preX);
            itercount++;
        }
        printf("newtonIter : the time of iter is %d
    ", itercount);
        return x;
    }

    4. 弦截法(又叫割线迭代法):其实就是将Newton迭代法中的导数换为插商。尽管比Newton迭代法少计算一个函数值,使得计算更简便,不过初始需要提供两个初始解。

    double chordIntercept(double x0, double x1, double err) {
        double preX;
        double x;
        double preF;
        double f;
    
        preX = x0;
        preF = func(preX);
        x = x1;
        f = func(x);
    
        double root = x - f * (x - preX) / (f - preF);
        int iterCount = 1;
        while (root - x > err) {
            preX = x;
            x = root;
            preF = f;
            f = func(root);
            root = x - f * (x - preX) / (f - preF);
            iterCount++;
        }
        printf("chordIntercept : the time of iter is %d
    ", iterCount);
        return root;
    }
  • 相关阅读:
    input 蓝边
    4.【ac自动机】模式串匹配
    3.【二叉树】最近公共祖先
    2.【动态规划】最长回文子串
    1. 【线段树】
    DbUtil
    oauth2
    cas
    Spring-security-web
    JSON Web Tokens
  • 原文地址:https://www.cnblogs.com/zhaoke271828/p/14033762.html
Copyright © 2020-2023  润新知