#include<stdio.h>
#include<stdlib.h>
#include<math.h>
/*最小二乘法拟合n阶多项式*/
void fit(const float* x, const float* y, int num_point, int n, float* coeff, float* mse)
{
//判断拟合阶次是否合法
if (n >= num_point)
{
printf("多项式的阶次不能大于等于坐标点数!");
return;
}
//构造线性方程组Ax=b,为矩阵A 和b分配内存空间
float** A = (float**)malloc(sizeof(float*) * (n + 1));
for (int i = 0; i < n+1; i++)
{
A[i] = (float*)malloc(sizeof(float) * (n + 1));
}
float* b = (float*)malloc(sizeof(float) * (n + 1));
//构造矩阵A和b
for (int k = 0; k < n + 1; k++)
{
for (int j = 0; j <= n + 1; j++)
{
float sum1 = 0;
for (int i = 0; i < num_point; i++)
{
sum1 += float(pow(x[i], k) * pow(x[i], j));
}
A[k][j] = sum1;
}
float sum2 = 0;
for (int i = 0; i < num_point; i++)
{
sum2 += float(pow(x[i], k) * y[i]);
}
b[k] = sum2;
}
//采用高斯消元法,将矩阵A变换为对角矩阵
for (int k = 0; k < n; k++)
{
for (int i = k + 1; i < n + 1; i++)
{
float m = A[i][k] / A[k][k];
for (int j = k + 1; j < n + 1; j++)
{
A[i][j] = A[i][j] - m * A[k][j];
}
b[i] = b[i] - m * b[k];
}
}
//高斯消元法回代,求出多项式系数
coeff[n] = b[n] / A[n][n];
for (int i = n - 1; i >= 0; i--)
{
float sum3 = 0;
for (int j = i + 1; j < n + 1; j++)
{
sum3 += A[i][j] * coeff[j];
}
coeff[i] = (b[i] - sum3) / A[i][i];
}
//求拟合的均方误差
float sum_sqr_err = 0;
for (int i = 0; i < num_point; i++)
{
float fx = 0;
for (int j = 0; j < n + 1; j++)
{
fx += coeff[j] * float(pow(x[i], j));
}
sum_sqr_err += (y[i] - fx) * (y[i] - fx);
}
*mse = sum_sqr_err / num_point;
//释放内存空间
/*
for (int i = 0; i < n + 1; i++)
{
free(A[i]);
}*/
free(A);
free(b);
}
int main()
{
float x[6]{ 1,2,4,6,8,10 };
float y[6]{ 1.8,3.7,8.2,12.0,15.8,20.2 };
int n = 2;//预估方程是二阶的,y=a0+a1*x+a2*x^2
int num_point = 6;
float coeff[3];//系数的个数为n+1,依次是a0,a1,a2
float mse;
fit(x, y, num_point, n, coeff, &mse);
printf("多项式系数:");
for (int i = 0; i < n + 1; i++)
{
printf("%lf ", coeff[i]);
}
printf("\n拟合均方误差:%lf\n", mse);
return 0;
}
评论26