- 注册时间
- 2009-5-22
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 38516
- 在线时间
- 小时
|
发表于 2010-2-8 17:33:37
|
显示全部楼层
#####
9#的贴子是在哈尔滨的香格里拉大酒店里发的。
做个记号,留作纪念。
#####
由于要参加ACM World Final的各项活动,所以睡前草草地编了一个C++程序跑起来就不管了。
我以为给她一个晚上的运行时间肯定足够了。
醒来后发现这个程序越跑越费劲,参数爬升了几级就爬不动了。
仔细一看才发现步长不合适了。
于是把步长改大几个数量级继续跑,然后我离开宾馆参加竞赛去了。
打完竞赛回到宾馆,发现参数又爬不动了。
于是再把步长改大,再跑一个晚上。
醒来后发现又不对劲了,参数爬升了几级又爬不动了。
然后才反应过来自己犯傻了,应该把步长设置为动态的!
修改完毕后再次运行,看到参数刷的一声至上云霄,瞬间登顶!
于是发贴汇报并自我检讨。
程序代码如下:- #include<cmath>
- #include<cstdio>
- #include<cstdlib>
-
- double x[180],y[180],a,p1,p2,p3,p4,p5,d1,d2,d3,d4,d5,min,tmp,b1,b2,b3,b4,b5;
- int i,n,t;
-
- double f(double x) //把x代入,计算f(x)的值
- {
- return p1/(p2+exp(p3*log(x)))+p4*exp(p5*log(x));
- }
-
- double ss() //把所有的x逐个代入,计算总偏差
- {
- int i;
- double s,s2;
- s2=0;
- for(i=0;i<n;i++)
- {
- s=f(x[i])-y[i]; //计算一个数据点的偏差
- s2+=s*s; //把偏差平方并累计
- }
- return s2;
- }
-
- int main()
- {
- scanf("%d",&n);
- for(i=0;i<n;i++)
- scanf("%lf%lf",&x[i],&y[i]); //读入数据
- p1=1.3738626629060553e+032; //设置初值
- p2=2.4369393036751976e+028; //设置初值
- p3=16.719431561664958; //设置初值
- p4=0.0012054475996989941; //设置初值
- p5=3.0453779404292880; //设置初值
- min=ss(); //计算偏差
- while(1) //死循环(在适当的时候人工终止运行,修改代码和参数,然后重新运行)
- {
- a=p1/1e12; //设置相对步长
- d1=(rand()-16384)*a; //设置绝对步长
- d2=(rand()-16384)*a/1e4; //设置绝对步长
- d3=rand()/1e13-1.6e-9; //设置绝对步长
- d4=rand()/1e16-1.6e-12; //设置绝对步长
- d5=rand()/1e14-1.6e-10; //设置绝对步长
- p1+=d1; //根据步长调整参数
- p2+=d2; //根据步长调整参数
- p3+=d3; //根据步长调整参数
- p4+=d4; //根据步长调整参数
- p5+=d5; //根据步长调整参数
- tmp=ss(); //计算调整参数后的偏差
- if(tmp<min) //如果偏差比原来小
- {
- min=tmp; //更新当前偏差,保留调整后的参数
- // t++; //累计更新次数
- // if(t>100) //每100次更新输出一次
- // {
- // t=0;
- printf("min=%lf\np1=%.0lf;\np2=%.0lf;\np3=%lf;\np4=%.9lf;\np5=%lf;\n\n",min,p1,p2,p3,p4,p5); //输出参数
- // }
- }
- else //如果偏差比原来大
- {
- p1-=d1; //还原参数
- p2-=d2; //还原参数
- p3-=d3; //还原参数
- p4-=d4; //还原参数
- p5-=d5; //还原参数
- }
- }
- return 0;
- }
复制代码 第一次做高难度的拟合作业,完全没有经验。
所以难以写出一气呵成的代码。
上述代码是跑跑停停,停停改改,改改又跑跑,才得到最终结果的。
其中$p_1$和$p_2$是分别从几百万和几千开始跑的。
然后眼看着它们一步一步地往上爬,一直没有停过。
最后才反应过来它们可能会直上云霄。
所以要把步长设置为相对的,而不是绝对的。
果然登顶的时候它们出奇的大,得用科学计数法来表示。
最后把步上逐渐减小,最终达到最佳拟合效果。
图是用curxpt软件画的。
curxpt软件自带拟合功能,但你这个数据它拟合不出来。
所以我才编了一个C++程序自己来拟合的。 |
|