首页 > 编程语言 >【c++】多项式曲线拟合

【c++】多项式曲线拟合

时间:2023-01-31 19:56:08浏览次数:59  
标签:曲线拟合 21 temp int 多项式 vecRow c++ ++ double

源代码,截取至数值分析期末大作业。其中一步为多项式曲线拟合,求解出符合拟合精度的函数表达式。

拟合和插值的区别?

  1.拟合:不必经过所有点

  2.插值:必须经过所有点

(1)曲线拟合

  

 

 (2)误差的计算

     

 

 (3)多项式曲线拟合

    

 

     

 

 步骤:

  1.设定k阶多项式

  2.计算ATAc*=ATy ,得出c*

  3.计算误差,满足要求停止计算

(4)方便理解的例题

    

 (5)代码计算使用的例题:

        

int NUM;
void qxnh(double c_final[100]) { double x[21][21]; double x_list[21] = { 0.000000,0.3149803,0.9999999,1.9655560,3.1748020,4.6050390,6.2402510, 8.068264,10.07937,12.26556,14.62009,17.13712,19.81156,22.63891, 25.61514,28.73660,31.99999,35.40231,38.94074,42.61273,46.41589 }; for (int i = 0;i < 21;i++) { x[i][0] = x_list[i]; } double y[21][21]; for (int i = 0;i < 21;i++) { y[i][0] = 0.5 * i; } //k次多项式进行拟合 x=φ(y) double A[21][21]; double AT[21][21]; double ATA[21][21]; double ATx[21][21]; double ATA_1[21][21]; double c[100]; double new_x[21]; double epsilon ; double new_ATx[21]; double c_mul[21][21]; for (int k = 0;k < 21;k++) { //int k = 5; for (int i = 0;i < 21;i++) { for (int j = 0;j < k;j++) { A[i][j] = pow(y[i][0], j); } } //求转置矩阵AT for (int i = 0;i < k;i++) { for (int j = 0;j < 21;j++) { AT[i][j] = A[j][i]; } } //矩阵相乘 ATA multi(AT, A, k-1, 20, k,ATA); //矩阵相乘 ATy multi(AT, x, k-1, 20, 1, ATx); //求解逆矩阵(ATA)-1 //inverse(ATA, k - 1, k - 1, ATA_1); //矩阵相乘 C=(ATA)-1ATy for (int i = 0;i < k;i++) { new_ATx[i] = ATx[i][0]; } //multi(ATA_1, ATx, k-1, 20, 0, c_mul); //解方程 equation_solver(ATA, new_ATx, c,k); //show(c, k, 1); double mid_y ; for (int i = 0;i < 21;i++) { mid_y = 0.0; for (int j = 0;j < k;j++) { mid_y += pow(y[i][0], j)*c[j]; } new_x[i] = mid_y; } epsilon = 0.0; for (int i = 0;i < 21;i++) { epsilon += pow(new_x[i] - x[i][0], 2); } std::cout << "epsilon " <<k<<": "<< epsilon << "\n"; if (epsilon <= 1e-6) { std::cout << "停止循环,此时k = " << k << ";多项式的阶数为:"<<k-1<<'\n'; NUM = k; for (int i = 0;i < k;i++) { c_final[i] = c[i]; } break; } } }

矩阵相乘:

void multi(double BT0[21][21], double B0[21][21], int m, int o, int n, double res[21][21]) {
    double BT[21][21];
    double B[21][21];
    double temp;
    for (int i = 0;i < 21;i++) {
        for (int j = 0;j < 21;j++) {
            BT[i][j] = BT0[i][j];
        }
    }
    for (int i = 0;i < 21;i++) {
        for (int j = 0;j < 21;j++) {
            B[i][j] = B0[i][j];
        }
    }
    for (int i = 0;i < m + 1;i++) {
        for (int j = 0;j < n + 1;j++) {
            temp = 0;
            for (int k = 0;k < o + 1;k++) {
                temp += BT[i][k] * B[k][j];
            }
            res[i][j] = temp;
        }
    }
    /*for (int i = 0;i < m + 1;i++) {
        for (int j = 0;j < n + 1;j++) {

            std::cout<<res[i][j]<<"   ";
        }
        std::cout << "\n";
    }*/
}

高斯法解方程:

void equation_solver(double dF_o[21][21], double F_o[21], double dx[100],int K) {
    int point = 0;
    double temp = 0.0;
    double dF[21][21];double F[21];

    //赋值
    for (int i = 0;i < K;i++) {
        for (int j = 0;j < K;j++) {
            dF[i][j] = dF_o[i][j];
        }
    }
    for (int i = 0;i < K;i++) {
        F[i] = F_o[i];
    }
    //选主元

    for (int k = 0;k < K-1;k++) {
        point = k;
        for (int l = k;l < K;l++) {
            if (fabs(dF[point][k]) < fabs(dF[l][k])) {
                point = l;
            }
        }
        //换行
        temp = 0;
        temp = F[point];
        F[point] = F[k];
        F[k] = temp;
        for (int l = k;l < K;l++) {
            temp = 0;
            temp = dF[point][l];
            dF[point][l] = dF[k][l];
            dF[k][l] = temp;
        }
        //消去过程
        double mid;
        for (int l = k + 1;l < K;l++) {
            mid = dF[l][k] / dF[k][k];
            F[l] = F[l] - mid * F[k];
            for (int p = 0;p < K;p++) {
                dF[l][p] -= mid * dF[k][p];
            }
        }
    }
   /* std::cout << "上三角: " << '\n';
    for (int i = 0;i < 4;i++) {
        for (int j = 0;j < 4;j++) {
            std::cout << "i" << i << "j" << j << "  " << dF[i][j] << "  ";
        }
        std::cout << "\n";
    }*/

    //求解方程
    int M = K - 1;
    dx[M] =F[M] / dF[M][M];
    for (int i = K-2;i > -1;i--) {
        temp = 0;
        //dx[i] = 0;
        for (int j = i + 1;j < K;j++) {
            temp += dF[i][j] * dx[j] / dF[i][i];
            //dx[i] -= dF[i][j] * dx[j] / dF[i][i];
        }
       dx[i] = F[i] / dF[i][i] - temp;
        //std::cout << "dx" << i << ": " << dx[i] << "\n";
    }

}

point1:更新矩阵乘法和解方程的代码。

详细见博客:

【c++】以函数调用的方式来书写矩阵乘法 - 致命一姬 - 博客园 (cnblogs.com)

【c++】列主元素高斯消去法求解方程 - 致命一姬 - 博客园 (cnblogs.com)

point2:避免全局变量NUM的使用

point3:使用函数重载来解决不同矩阵对矩阵乘法的需求

最后实现计算多项式曲线拟合的代码如下:

#include <iostream>
#include <vector>
#include <cassert>
#include <math.h>

using vec = std::vector<std::vector<double>>;
using vecRow = std::vector<double>;

vec multi(vec A, vec B) {
    int row1{ static_cast<int> (A.size()) };
    int col1{ static_cast<int>(A[0].size()) };
    int row2{ static_cast<int>(B.size()) };
    int col2{ static_cast<int>(B[0].size() )};
    vec res(row1, vecRow(col2));
    double temp{};
    assert(col1 == row2 && "第一个矩阵的列和第二个矩阵的行不相等");
    for (int i = 0;i != row1;++i) {
        for (int j = 0;j != col2;++j) {
            temp = 0;
            for (int k = 0;k != col1;++k) {
                temp += A[i][k] * B[k][j];
            }
            res[i][j] = temp;
        }
    }
    return res;
}

vecRow multi(vec A, vecRow B) {
    int row1{ static_cast<int> (A.size()) };
    int col1{ static_cast<int>(A[0].size()) };
    int row2{ static_cast<int>(B.size()) };
    int col2{ 1 };
    vecRow res(row1);
    double temp{};
    assert(col1 == row2 && "第一个矩阵的列和第二个矩阵的行不相等");
    for (int i = 0;i != row1;++i) {
        temp = 0;
        for (int j = 0;j != row2;++j) {
            temp += A[i][j] * B[j];
        }
        res[i] = temp;
    }
    return res;
}



vecRow equationSolver(vec A, vecRow B) {   //如果这里为vec&A vecRow&B ,则A和B的值会改变。如果没有&,则不变,改变的为A和B的副本
    int row1{ static_cast<int> (A.size()) };
    int col1{ static_cast<int>(A[0].size()) };
    int row2{ static_cast<int>(B.size()) };
    assert((row1 == row2) || (row1 > 0) && "请检查输入");
    int point;
    double temp;
    double m;
    vecRow x(row1);
    if (row1 == 1) {
        x[row1] = B[row1] / A[row1][row1];
        return x;
    }
    //一列一列来
    for (int k = 0;k != col1 - 1;++k) {
        //选主元
        point = k;
        //寻找k列中绝对值最大的数的行point
        for (int r = k;r != row1;++r) {
            if (fabs(A[point][k]) < fabs(A[r][k])) {
                point = r;
            }
        }
        //判断A是否为奇异矩阵
        assert(fabs(A[point][k]) > 1e-6 && "A为奇异矩阵");
        //换行
        temp = B[k];
        B[k] = B[point];
        B[point] = temp;
        for (int i = 0;i != col1;++i) {
            temp = A[point][i];
            A[point][i] = A[k][i];
            A[k][i] = temp;
        }
        //消去
        m = 0.0;
        for (int i = k + 1;i != col1;++i) {
            m = A[i][k] / A[k][k];
            B[i] -= m * B[k];
            for (int j = 0;j != col1;++j) {
                A[i][j] -= m * A[k][j];
            }
        }
    }
    //解方程
    double sum{ 0.0 };
    x[row1 - 1] = B[row1 - 1] / A[row1 - 1][row1 - 1];
    for (int i = row1 - 2;i >= 0;--i) {
        sum = 0.0;
        for (int j = i + 1;j != col1;++j) {
            sum += A[i][j] * x[j] / A[i][i];
        }
        x[i] = B[i] / A[i][i] - sum;
    }
    /*for (double i : x) {
        std::cout << i << "  ";
    }*/
    return x;
}


//计算转置矩阵
vec transpose(vec A) {
    int row{ static_cast<int> (A.size()) };
    int col{ static_cast<int>(A[0].size()) };
    vec B(col, vecRow(row));
    for (int i = 0;i != row;++i) {
        for (int j = 0;j != col;++j) {
            B[j][i] = A[i][j];
        }
    }
    return B;
}

//计算多项式拟合的结果
vecRow compute(vecRow c, vecRow y) {
    int row_c{ static_cast<int> (c.size()) };
    int row_y{ static_cast<int> (y.size()) };
    double temp{};
    vecRow result(row_y);
    for (int i = 0;i != row_y;++i) {
        temp = 0.0;
        for (int j = 0;j != row_c;++j) {
            temp += pow(y[i], j)*c[j];
        }
        result[i] = temp;
    }
    return result;
}


//计算误差
double epsilon(vecRow A, vecRow B) {
    int row_A{ static_cast<int> (A.size()) };
    int row_B{ static_cast<int> (B.size()) };
    assert(row_A == row_B, "please check the input");
    double mid{};
    for (int i = 0;i != row_A;++i) {
        mid += pow(A[i] - B[i], 2);
    }
    return mid;
}

//返回方程求解的结果vecRow c,然后具体的k可以通过计算c的大小得出
//传入x=φ(y)的x和y
vecRow qxnh(vecRow x,vecRow y) {
    int k{ 2 };
    int row_x{ static_cast<int> (x.size()) };
    int row_y{ static_cast<int> (y.size()) };
    assert(row_x == row_y, "please check the input");
    double ep{};
    vecRow result(row_x);
    while (1) {
        //构建A
        vec A(row_x, vecRow(k));
        for (int i = 0;i!= row_y;++i) {
            for (int j = 0;j != k;++j) {
                A[i][j] = pow(y[i], j);
            }
        }
        vec AT{ transpose(A) };
        //ATA
        vec ATA{ multi(AT,A) };
        //ATy,该例中,y为x。函数重载
        vecRow ATy{ multi(AT, x) };
        vecRow c{ equationSolver(ATA,ATy) };
        result = compute(c, y);
        ep = epsilon(result, x);
        if (ep <= 1e-6) {
            std::cout << "停止循环,此时k = " << k << ";多项式的阶数为:" << k - 1 << '\n';
            return c;
        }
        else {
            ++k;
        }
    }
}

void show(vec A) {
    for (vecRow i : A) {
        for (double j : i) {
            std::cout << j << " ";
        }
        std::cout << '\n';
    }
}

void show(vecRow A) {
    for (double i : A) {
        std::cout << i << " ";
        std::cout << '\n';
    }
}


int main()
{
    vecRow x{ 0.000000,0.3149803,0.9999999,1.9655560,3.1748020,4.6050390,6.2402510,
                     8.068264,10.07937,12.26556,14.62009,17.13712,19.81156,22.63891,
                     25.61514,28.73660,31.99999,35.40231,38.94074,42.61273,46.41589 };
    //int k ;
    int row_x{ static_cast<int> (x.size() )};
    vecRow y(row_x);
    for (int i = 0;i != row_x;++i) {
        y[i] = 0.5 * i;
    }
    qxnh(x,y);
}

 

标签:曲线拟合,21,temp,int,多项式,vecRow,c++,++,double
From: https://www.cnblogs.com/zhimingyiji/p/17080310.html

相关文章

  • C++信奥赛题目 1154:亲和数
    1154:亲和数时间限制:1000ms      内存限制:65536KB提交数:41239   通过数:24946【题目描述】自然数a的因子是指能整除a的所有自然数,但不含a本......
  • 【KAWAKO】在windows上用CMake和MinGW编译c++工程
    目录安装CMake安装MinGW编写CMakeLists.txt编译一条龙安装CMake在网上随便找个教程照着安装就行了,不再赘述。安装MinGW参考这篇博客。从MinGW官网下载的安装包在安装的......
  • 【KAWAKO】TVM-使用c++进行推理
    目录前言修改cpp_deploy.cc文件修改DeployGraphExecutor()函数numpy与bin文件的互相转换numpy转binbin转numpy使用CMakeLists.txt进行编译运行前言在tvm工程的apps目录下......
  • c++
    #include<iostream>usingnamespacestd;intmain(intargc,char**argv){ inta; cin>>a; if(a==95||a==96||a==97||a==98||a==99||a==100){ cout<<"你获得了......
  • 小熊猫C++错误【Permission denied】与纠正
    问题很早以前,在使用VisualStudioC++时,就经常遭遇到如题所示的编译链接错误。【Permissiondenied】的意思很明确:无权限,不允许操作。什么原因导致这种错误呢?请大家结合自己......
  • C++知识点捕捉
    1.对于提高cin运行时间代码:ios::sync_with_stdio(false); cin.tie(0);//cin.tie(nullptr);减少运行时间,scanf永远的神13倍,……………………………………2、......
  • C++运算符重载引用传参与返回引用的小小心得
    1#include<bits/stdc++.h>23usingnamespacestd;45//平面向量类,提供完成向量运算和比较的API6//除递增运算符和左移运算符重载外其他函数省略78......
  • 小熊猫C++编写海龟作图程序
    未完待续。。。初遇问题使用内置的模板创建海龟作图小程序:但是,编译运行时出现错误:rturtle海龟绘图命令小结在小海龟行动之前,我们需要熟悉一下绘图环境。这里用列表小结一下......
  • C++ 编译相关
    目录一、cmake前言安装步骤二、cmake与make两者区别为什么不直接使用项目编译链接工具(gcc/g++...)为什么不直接使用make或者Ninjacmake指定编译器(cmake-G)三、CMakeLists......
  • C++ STL stack
    #include<stack>头文件usingnamespacestd;作用这个很清楚了,FILO运用在:括号匹配、波兰式计算问题上(未完待续)创建一个参数,默认使用deque容器stack<typenameT,t......