搜索
bottom↓
回复: 24

分享:N点的多项式拟合曲线,C代码

  [复制链接]

出0入0汤圆

发表于 2018-10-13 21:23:39 | 显示全部楼层 |阅读模式
本帖最后由 xuhai777 于 2018-10-13 21:42 编辑

已知N个样本点,用多项式拟合过这N个点的曲线.
理论的话就不多说了.
n次多项式:Y=ax^n+bx^(n-1)...fx^1+g
已知n次多项式的(n+1)个样本,用消元法求解多项式的系数
思路:
1)多项式按X的幂由低到高排序格式
  a+bx+cx^2...+gx^n=Y
2)转换格式:n次则有(n+1)系数,加上Y值,所以列数是(n+2)
  a,b,c...g,y
3)把(n+1)个样本组数分别代入,并计算X的幂,书写矩阵格式,行数是(n+1)
4)从左到右顺序设置主系数,开始消元并归1化,直到第n系数先被计算出来
  消元:已归1化后的行,异行同列相减,可使主系数为0
  归1化:行内全部系数除以主系数
5)把n系数回代入(n-1)行,计算(n-1)系数
  再把n和(n-1)系数回代入(n-2)行,计算(n-2)系数
  依此法,直到计算出全部系数,系数在末列
限制条件:
样本唯一的x值对应唯一的y值,也就是多项式的曲线不能分叉

例举:已知3点{1,2 ,2,4 ,4,3},求过此3点的多项式曲线
解法:设此曲线的多项式为 a+bx+cx^2=Y
(1)分别代入3点数据,列出矩阵式
  1 1 1  2  行1
  1 2 4  4  行2
  1 4 16 3  行3
(2)消元并归1化,计算出n系数
  行2=行2-行1 ;行3=行3-行1
   1 1 1  2  行1
=> 0 1 3  2  行2
   0 3 15 1  行3
  行3归1化
   1 1 1 2    行1
=> 0 1 3 2    行2
   0 1 5 1/3  行3
  行3=行3-行2
   1 1 1 2     行1
=> 0 1 3 2     行2
   0 0 2 -5/3  行3
  行3归1化
   1 1 1 2     行1
=> 0 1 3 2     行2
   0 0 1 -5/6  行3
(3)回代,直到计算出全部系数
  行3代入行2
   1 1 1 2     行1
=> 0 1 0 9/2   行2
   0 0 1 -5/6  行3
  行3行2代入行1
   1 0 0 -5/3  行1
=> 0 1 0 9/2   行2
   0 0 1 -5/6  行3
(4)所求多项式
  -5/3 +9/2x -5/6x^2 =Y

C语言代码
//float s[]={1,2 ,2,4 ,4,3 ,5,2 ,7,-1 ,7.5,0.5}; //样本:x,y
float s[]={1,2 ,2,4 ,4,3 ,5,2 ,7,-1 ,6,0.5}; //样本:x,y
//float s[]={1,2 ,2,4 ,3,6}; //直线,计算结果中无用系数是0
#define n (sizeof(s)/sizeof(float)/2) //样本组数,行数
#define m (n+1) //矩阵行变量数
//---------------------------
float Pow(float i,int j) //幂函数,x^0=1;x^1=x
{ float k=1;
  while(j--) { k*=i; };
  return(k);
}
void poly(void)
{ int i,j,k,z,r;
  float t[n*m],w; //n*(n+1),计算用的矩阵数组,计算结果在末列
  if(n>1)
  { z=0; k=0; //初始化矩阵,顺序:x^0,x^1,x^2...y
    for(j=0;j<n;j++)
    { w=s[k++]; //X值
      for(i=0;i<n;i++) //第一列总是1,没优化
      { t[z++]=Pow(w,i); } //X的幂计算
      t[z++]=s[k++]; //Y值
    }
    //-----------------------
    for(k=0;k<n;k++) //总元数
    { z=k*m; //初行,参考行
      for(j=k+1;j<n;j++) //行数
      { r=j*m; //始行,消元行
        for(i=k;i<m;i++) //列数
        { t[r+i]-=t[z+i]; } //消元
        r++;
        if(t[r+k]!=1) //行元位置
        { for(i=k+1;i<n;i++) //列数
          { t[r+i]/=t[r+k]; } //行归1化
          t[r+k]=1; //为了好看
        }
      }
    }
    //-----------------------
    for(j=n-1;j>0;j--) //行
    { w=0;
      for(i=j;i<n;i++) //列
      { w+=t[m*(j-1)+i]*t[m*(i+1)-1]; }
      t[m*j-1]-=w; //计算行Y植
      z=m*(j-1); for(i=j;i<n;i++) { t[z+i]=0; } //为了好看
    }
  }
  while(1); //断点
}
//===========================
int main(void)
{ poly();
  while(1);
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2018-10-13 21:24:49 | 显示全部楼层
总结:
1)过有限点的多项式曲线,实际有无数条,因为无穷次多项式可以过有限点.
2)当多项式的项数仅比样本多1时,仅能确定1条曲线.
3)新样本X值在旧样本X范围之外,则新样本Y不可预测;
  之内,则新样本Y与原曲线的插值Y偏差较小(相对Ymax~Ymin范围).

出0入0汤圆

 楼主| 发表于 2018-10-13 21:27:55 | 显示全部楼层
这个多项式拟合曲线有什么用啊?
只能做插值.不能做预测.
想用它来预测股票走势是不可能的了

出0入0汤圆

 楼主| 发表于 2018-10-13 21:28:37 | 显示全部楼层
这个多项式拟合曲线有什么用啊?
只能做插值.不能做预测.
想用它来预测股票走势是不可能的了

出0入0汤圆

 楼主| 发表于 2018-10-13 21:32:45 | 显示全部楼层
长宽网络上传不了图片,只有文字版了

出0入0汤圆

发表于 2018-10-13 21:34:21 来自手机 | 显示全部楼层
你这自问自答的挺嗨啊。标题注意一下?

出0入0汤圆

 楼主| 发表于 2018-10-13 21:43:14 | 显示全部楼层
No.5 发表于 2018-10-13 21:34
你这自问自答的挺嗨啊。标题注意一下?

谢谢提醒

出0入0汤圆

发表于 2018-10-13 21:45:16 | 显示全部楼层
好资料,学习了

出0入0汤圆

发表于 2018-10-13 22:06:02 | 显示全部楼层
最小二乘

出0入8汤圆

发表于 2018-10-13 23:17:58 来自手机 | 显示全部楼层
最近刚好需要,收藏一下

出20入25汤圆

发表于 2018-10-13 23:22:10 来自手机 | 显示全部楼层
感觉用梯度下降之类更简单的,这个最小二乘计算还是比较复杂

出0入0汤圆

发表于 2018-10-14 00:29:56 | 显示全部楼层
看不懂有啥用,有没有多点校正的例子

出0入0汤圆

发表于 2018-10-14 07:12:50 来自手机 | 显示全部楼层
感谢楼主分享

出0入0汤圆

发表于 2018-10-14 08:07:00 来自手机 | 显示全部楼层
全是r,j,i,k的代码可读性太差了。。。

出0入0汤圆

发表于 2018-10-14 14:25:31 | 显示全部楼层
N点的多项式拟合曲线

出0入0汤圆

 楼主| 发表于 2018-10-14 16:20:52 | 显示全部楼层
nanfang2000 发表于 2018-10-14 08:07
全是r,j,i,k的代码可读性太差了。。。

我也想知道怎么可以"看一眼就知道整段程序代码是实现什么功能,而且还能看明白每行代码运行的细节"

出0入0汤圆

 楼主| 发表于 2018-10-14 16:25:20 | 显示全部楼层
做图验证可以用SketchPad(几何画板),长宽网络上传不了

出0入0汤圆

发表于 2018-10-14 23:05:50 | 显示全部楼层

LZ说的是拟合成一元高次方程,是可以曲线的;而最小二乘法拟合出来的是一元一次线性方程

出0入0汤圆

发表于 2018-10-15 08:45:48 | 显示全部楼层
其实没有看的很明白。
就是有样本,原来的插值计算没有这样的计算更精确?

出10入23汤圆

发表于 2018-10-15 08:47:26 来自手机 | 显示全部楼层
locky_z 发表于 2018-10-14 23:05
LZ说的是拟合成一元高次方程,是可以曲线的;而最小二乘法拟合出来的是一元一次线性方程 ...

你确定你的知识没搞错?

出0入0汤圆

发表于 2018-10-15 09:15:44 | 显示全部楼层
locky_z 发表于 2018-10-14 23:05
LZ说的是拟合成一元高次方程,是可以曲线的;而最小二乘法拟合出来的是一元一次线性方程 ...

最小二乘是能处理高次曲线的,我甚至做过椭球拟合
非线性函数最小二乘也是能够处理的

出0入8汤圆

发表于 2018-10-15 11:35:34 | 显示全部楼层
怎么使用呢?有demo吗

出10入23汤圆

发表于 2018-10-15 12:19:08 来自手机 | 显示全部楼层
s1j2h3 发表于 2018-10-15 09:15
最小二乘是能处理高次曲线的,我甚至做过椭球拟合
非线性函数最小二乘也是能够处理的


是的,多项式的最小二乘法拟合是可以直接计算出参数的,其他函数的最小二乘法拟合通常就需要用到迭代了

出0入0汤圆

发表于 2018-10-15 12:59:22 | 显示全部楼层
zouzhichao 发表于 2018-10-15 12:19
是的,多项式的最小二乘法拟合是可以直接计算出参数的,其他函数的最小二乘法拟合通常就需要用到迭代了 ...

同道中人

出0入0汤圆

发表于 2018-10-20 18:33:51 来自手机 | 显示全部楼层
楼主还想预测股票
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 18:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表