写完这些程序还是很有感触的,以前从来没有考虑过误差之类的东西,认为double 16位的精度无所不能~
又想起ac poj 3155那个纠结的时刻,把精度调高居然还wa了!!去问sphinx,他说他也有好多题目是这样,然后我居然在poj 3155的discuss里说这题的测试数据有误。。。- -!汗,直到前几个星期我才意识到错的还是我,学了数值分析才知道有些时候并不是精度越高结果就越准确,在控制double的精度的时候不要让它小于1e-14,在考虑截断误差的同时不要忘了舍入误差,也许poj 3155就是因为在精度设置过高的时候舍入误差产生了很大的影响才wa的吧~
/* 拉格朗日插值
*/
#include<iostream>
using namespace std;
const int maxn = 1001;
double x[maxn];
double y[maxn];
double c[maxn]; // ²åֵϵÊýc
double x0,ans;
int n;
double Lagrange()
{
double temp;
for(int k=0;k<=n;k++) //±éÀúËùÓеĵã
{
temp = 1.0;
for(int u=0;u<=n;u++) if(u != k)
{
temp *= x[k] - x[u];
}
c[k] = y[k] / temp;
}
ans = 0.0;
for(int k=0;k<=n;k++)
{
temp = c[k];
for(int u=0;u<=n;u++) if(u != k)
{
temp *= x0 - x[u];
}
ans += temp;
}
return ans;
}
void init() //³õʼ»¯Ã¿¸öµã
{
printf("ÊäÈëÐèÒªÇó½âµÄx0: -> ");
cin>>x0;
printf("\nÇëÊäÈëÒÑÖªµãµÄ¸öÊý: -> ");
cin>>n;
n--;
printf("\n·Ö±ðÊäÈëÿ¸öµã:\n");
for(int i=0;i<=n;i++)
{
printf("\nµÚ%d¸öµã: -> ",i);
cin>>x[i]>>y[i];
}
return ;
}
int main()
{
init();
printf("\nLagrange²åÖµ½á¹ûΪ : ");
cout<<Lagrange()<<endl;
getchar();
getchar();
return 0;
}
/*---- ²âÊÔÊý¾Ý --------*
115
3
100 10
121 11
144 12
----------------------------*/
/* 埃特金插值
*/
#include<iostream>
#include<iomanip>
using namespace std;
const int maxn = 1001;
double f[maxn][maxn];
double x[maxn];
double y[maxn];
double x0;
int n;
void Aitken()
{
cout.setf(ios::fixed);
cout<<endl<<endl<<f[0][0]<<endl;
for(int k=1;k<=n;k++)
{
cout<<f[0][k]<<" | ";
for(int u=1;u<=k;u++)
{
f[u][k] = (x0 - x[k])*f[u-1][u-1]/(x[u-1]-x[k]) + (x0-x[u-1])*f[u-1][k]/(x[k]-x[u-1]);
if(u!=k)
{
cout<<setprecision(6)<<f[u][k]<<" | ";
}
else
{
cout<<setprecision(6)<<f[u][k]<<endl;
}
}
}
return ;
}
void init() //³õʼ»¯Ã¿¸öµã
{
printf("ÊäÈëÐèÒªÇó½âµÄx0: -> ");
cin>>x0;
printf("\nÇëÊäÈëÒÑÖªµãµÄ¸öÊý: -> ");
cin>>n;
n--;
printf("\n·Ö±ðÊäÈëÿ¸öµã:\n");
for(int i=0;i<=n;i++)
{
printf("\nµÚ%d¸öµã: -> ",i);
cin>>x[i]>>y[i];
}
for(int i=0;i<=n;i++)
{
f[0][i] = y[i];
}
return ;
}
int main()
{
init();
Aitken();
getchar();
getchar();
return 0;
}
/*----- ²âÊÔÊý¾Ý -------*
0.462
5
0.3 0.29850
0.4 0.39646
0.5 0.49311
0.6 0.58813
0.7 0.68122
-----------------------------*/
/* 牛顿插值
*/
#include<iostream>
using namespace std;
const int maxn = 1001;
double x[maxn];
double y[maxn];
double c[maxn]; //ÐÞÕýϵÊýc
double x0;
int n;
double Newton()
{
double tmp;
double tmp2;
double tmp3;
c[0] = y[0];
for(int k=1;k<=n;k++)
{
tmp = 0.0;
for(int u=0;u<k;u++)
{
tmp2 = c[u];
for(int i=0;i<u;i++)
{
tmp2 *= x[k]-x[i];
}
tmp += tmp2;
}
tmp3 = 1.0;
for(int i=0;i<k;i++)
{
tmp3 *= x[k]-x[i];
}
c[k] = (y[k]-tmp) / tmp3;
}
double ans=0.0;
double temp;
for(int k=0;k<=n;k++)
{
temp = c[k];
for(int i=0;i<k;i++)
{
temp *= x0-x[i];
}
ans += temp;
}
return ans;
}
void init() //³õʼ»¯Ã¿¸öµã
{
printf("ÊäÈëÐèÒªÇó½âµÄx0: -> ");
cin>>x0;
printf("\nÇëÊäÈëÒÑÖªµãµÄ¸öÊý: -> ");
cin>>n;
n--;
printf("\n·Ö±ðÊäÈëÿ¸öµã:\n");
for(int i=0;i<=n;i++)
{
printf("\nµÚ%d¸öµã: -> ",i);
cin>>x[i]>>y[i];
}
return ;
}
int main()
{
init();
printf("\nÅ£¶Ù²åÖµµÄ½á¹ûΪ : ");
cout<<Newton()<<endl;
getchar();
getchar();
return 0;
}
/*---- ²âÊÔÊý¾Ý --------*
115
3
100 10
121 11
144 12
----------------------------*/
/*---- 复化辛甫生公式--数值积分 ------
----- ¸´»¯ÐÁ¸¦Éú¹«Ê½ ----*/
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 111;
const double eps = 1e-12;
double x[maxn];
double h;
double f(double x)
{
if(x<eps)
{
return 1.0;
}
return sin(x) / x;
}
double xfs() // 0 --> 1
{
double h = 1.0/100;
for(int i=1;i<=100;i++)
{
x[i] = x[i-1] + h;
}
double ans = 0.0;
double temp;
for(int i=1;i<=100;i++)
{
temp = h/6.0;
temp *= f(x[i-1]) + 4*f((x[i-1]+x[i])/2.0) + f(x[i]);
ans += temp;
printf("%.2lf | %.2lf | %.6lf \n",x[i-1],x[i],temp);
}
return ans;
}
inline void init()
{
memset(x,0,sizeof(x));
return ;
}
int main()
{
init();
printf("answer is : %.12lf\n\n",xfs());
getchar();
return 0;
}
/*---- 复化柯特斯公式--数值积分 ------
----- ¸´»¯¿ÂÌØ˹¹«Ê½ ----*/
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 111;
const double eps = 1e-12;
double x[maxn];
double h;
double f(double x)
{
if(x<eps)
{
return 1.0;
}
return sin(x) / x;
}
double xfs() // 0 --> 1
{
double h = 1.0/100;
for(int i=1;i<=100;i++)
{
x[i] = x[i-1] + h;
}
double ans = 0.0;
double temp;
for(int i=1;i<=100;i++)
{
temp = h/90.0;
temp *= ( + 7.0 * f(x[i-1])
+ 32.0 * f(x[i-1]+h/4.0)
+ 12.0 * f((x[i-1]+x[i])/2.0)
+ 32.0 * f(x[i]-h/4.0)
+ 7.0 * f(x[i])
);
ans += temp;
printf("%.2lf | %.2lf | %.6lf \n",x[i-1],x[i],temp);
}
return ans;
}
inline void init()
{
memset(x,0,sizeof(x));
return ;
}
int main()
{
init();
printf("answer is : %.12lf\n\n",xfs());
getchar();
return 0;
}
/* 复化高斯公式
* ÊýÖµ»ý·Ö
*/
#include<iostream>
#include<cmath>
using namespace std;
const double eps = 1e-8;
const int maxn = 100;
double x[maxn+1];
double f(double x)
{
if(x<eps)
{
return 1.0;
}
return sin(x)/x;
}
double gauss()
{
double h = 1.0/maxn;
double cx1 = ( 1.0 - sqrt(1.0/3.0) ) / 2.0;
double cx2 = ( 1.0 + sqrt(1.0/3.0) ) / 2.0;
double x1,x2,temp;
double ans = 0.0;
for(int i=1;i<=maxn;i++)
{
x1 = x[i-1] + (x[i] - x[i-1])*cx1;
x2 = x[i-1] + (x[i] - x[i-1])*cx2;
temp = f(x1) + f(x2);
temp /= 2.0;
temp *= h;
ans += temp;
}
return ans;
}
void init()
{
double h = 1.0 /maxn;
memset(x,0,sizeof(x));
for(int i=1;i<=maxn;i++)
{
x[i] = x[i-1] + h;
}
return ;
}
int main()
{
init();
printf("answer is : %.12lf\n",gauss());
getchar();
return 0;
}
/*------ 龙贝格加速算法 ---------
------ Áú±´¸ñ¼ÓËÙËã·¨ --------*/
#include<iostream>
#include<cmath>
using namespace std;
const double eps = 1e-6;
const int maxn = 22;
const int maxstep = 22;
const int maxc = 1<<22;
double x[maxc];
double t[maxn];
double s[maxn];
double c[maxn];
double r[maxn];
double f(double x)
{
if(x<eps)
{
return 1.0;
}
return sin(x)/x;
}
double gets(int id)
{
s[id] = t[id+1]*4.0/3.0 - t[id]/3.0;
return s[id];
}
double getc(int id)
{
c[id] = s[id+1]*16.0/15.0 - s[id]/15.0;
return c[id];
}
double getr(int id)
{
r[id] = c[id+1]*64.0/63.0 - c[id]/63.0;
return r[id];
}
double lbg()
{
double ans=0.0;
double pre = 0;
double now=1000;
int step = 1;
int steps = 0;
int stepc = 0;
int stepr = 0;
double temp;
double h;
printf("| t | s | c | r |\n");
printf("| %.6lf | \n",t[0]);
while( abs(pre - now) > eps || step < maxstep) //¶þ·Ö²½³¤
{
if(stepc >= 1) pre = now;
h = 1.0/(1<<step);
temp = 0.0;
for(int i=1; i <= (1 << step); i++) if(i & 1)
{
temp += f(i * h);
}
temp *= h;
t[step] = t[step - 1] / 2.0 + temp;
printf("| %.6lf | ",t[step]);
if(step >= 1)
{
gets(step - 1);
printf("%.6lf | ",s[step-1]);
steps = step - 1;
}
if(steps >= 1)
{
getc(steps -1);
stepc = steps -1;
printf("%.6lf | ",c[steps-1]);
}
if(stepc >= 1)
{
now = getr(stepc - 1);
stepr = stepc - 1;
printf("%.6lf | ",r[stepc-1]);
}
step ++;
cout<<endl;
}
return now;
}
void init()
{
memset(t,0,sizeof(t));
memset(s,0,sizeof(s));
memset(c,0,sizeof(c));
memset(r,0,sizeof(r));
t[0] = (f(0) + f(1))/2.0;
return ;
}
int main()
{
init();
printf("\nans is : %.12lf \n",lbg());
getchar();
return 0;
}
/*数值微分中点方法
* ±ä²½³¤Öе㷽·¨
*/
#include<iostream>
#include<cmath>
using namespace std;
const double eps = 1e-8;
inline double f(double x)
{
return exp(x);
}
double find()
{
double h = 0.8;
double pre=123456789;
double now=987654321;
double a = 1.0;
double l,r;
while(abs(pre-now) > eps)
{
pre = now;
l = a - h;
r = a + h;
l = f(l);
r = f(r);
now = (r - l) / (2.0 * h);
h /= 2.0;
}
return now;
}
int main()
{
printf("answer is : %.12lf \n",find());
getchar();
return 0;
}
/* 两步欧拉格式
*/
#include<iostream>
#include<cmath>
using namespace std;
const double eps = 1e-8;
const int maxn = 10;
double x[maxn+1];
double y[maxn+1];
double f(double x,double y)
{
return y - 2.0*x/y;
}
void Two_step_euler_format()
{
double h = 1.0/maxn;
for(int i=2;i<=maxn;i++)
{
y[i] = y[i-2] + 2.0*h*f(x[i-1],y[i-1]);
}
for(int i=1;i<=maxn;i++)
{
cout<<x[i]<<" | ";
printf("%.6lf\n",y[i]);
}
return ;
}
void init()
{
double h = 1.0/maxn;
x[0] = 0.0;
y[0] = 1.0;
for(int i=1;i<=maxn;i++)
{
x[i] = x[i-1] + h;
}
y[1] = y[0] + h * f(x[0] , y[0]);
return ;
}
int main()
{
init();
Two_step_euler_format();
getchar();
return 0;
}
/* 改进欧拉格式
* ³£Î¢·Ö·½³ÌµÄ²î·Ö·½·¨
*/
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 100;
const double eps = 1e-8;
double x[maxn+1];
double y[maxn+1];
double f(double x,double y)
{
return y - 2.0*x/y;
}
void Improved_euler_scheme()
{
double h = 1.0/maxn;
for(int i=1;i<=maxn;i++)
{
y[i] = y[i-1] + h*f(x[i-1],y[i-1]);
y[i] = y[i-1] + h/2.0*(f(x[i-1],y[i-1]) + f(x[i],y[i]));
}
for(int i=1;i<=maxn;i++)
{
cout<<x[i]<<" | ";
printf("%.6lf\n",y[i]);
}
return ;
}
void init()
{
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
y[0]=1.0;
double h = 1.0/maxn;
for(int i=1;i<=maxn;i++)
{
x[i] = x[i-1] + h;
}
return ;
}
int main()
{
init();
Improved_euler_scheme();
getchar();
return 0;
}
/* 四阶龙格库塔经典格式
* ³£Î¢·Ö·½³Ì
*/
#include<iostream>
#include<cmath>
using namespace std;
const double eps = 1e-8;
const int maxn = 10;
double x[maxn+1];
double y[maxn+1];
double f(double x,double y)
{
return y - 2.0*x/y;
}
void start()
{
double k1,k2,k3,k4;
double mid;
double h = 1.0/maxn;
for(int i=1;i<=maxn;i++)
{
mid = (x[i-1]+x[i])/2.0;
k1 = f(x[i-1],y[i-1]);
k2 = f(mid,y[i-1]+h/2.0*k1);
k3 = f(mid,y[i-1]+h/2.0*k2);
k4 = f(x[i],y[i-1]+h*k3);
y[i] = y[i-1] + h/6.0*(k1 + 2*k2 + 2*k3 + k4);
}
for(int i=1;i<=maxn;i++)
{
cout<<x[i]<<" | ";
printf("%.6lf\n",y[i]);
}
return ;
}
void init()
{
double h = 1.0/maxn;
x[0]=0.0;
y[0]=1.0;
for(int i=1;i<=maxn;i++)
{
x[i] = h + x[i-1];
}
return ;
}
int main()
{
init();
start();
getchar();
return 0;
}
/* 变步长的龙格库塔格式
* ΢·Ö·½³Ì²î·Ö·½·¨
*/
#include<iostream>
#include<cmath>
using namespace std;
const double eps = 1e-14;
const int maxn = 1<<20;
double x[maxn+1];
double y[maxn+1];
void init(int step);
double f(double x,double y)
{
return y - 2.0*x/y;
}
void start()
{
double k1,k2,k3,k4;
double mid;
int step = 1;
double h;
double pre=123456789;
double now=987654321;
while(abs(pre-now) > eps && step < maxn)
{
init(step);
h = 1.0/step;
pre = now;
for(int i=1;i<=step;i++)
{
mid = (x[i-1]+x[i])/2.0;
k1 = f(x[i-1],y[i-1]);
k2 = f(mid,y[i-1]+h/2.0*k1);
k3 = f(mid,y[i-1]+h/2.0*k2);
k4 = f(x[i],y[i-1]+h*k3);
y[i] = y[i-1] + h/6.0*(k1 + 2*k2 + 2*k3 + k4);
}
now = y[step];
for(int i=1;i<=step;i++)
{
printf("%.6lf | %.12lf\n",x[i],y[i]);
}
printf("Now it has been divided into %d part\n",step);
getchar();
step<<=1;
}
if(abs(now-pre)<eps)
{
printf("exit successful!\n");
}
else
{
printf("error!\n");
}
return ;
}
void init(int step)
{
double h = 1.0/step;
x[0]=0.0;
y[0]=1.0;
for(int i=1;i<=step;i++)
{
x[i] = h + x[i-1];
}
return ;
}
int main()
{
start();
getchar();
return 0;
}
/* 四阶亚当姆斯格式
* ΢·Ö·½³Ì²î·Ö·½·¨
*/
#include<iostream>
using namespace std;
const double eps = 1e-8;
const int maxn = 10;
double x[maxn];
double y[maxn];
double f(double x,double y)
{
return y - 2.0*x/y;
}
void start()
{
double k1,k2,k3,k4;
double mid;
double h = 1.0/maxn;
for(int i=1;i<=3;i++) //ËĽ׾µä¸ñʽ
{
mid = (x[i-1]+x[i])/2.0;
k1 = f(x[i-1],y[i-1]);
k2 = f(mid,y[i-1]+h/2.0*k1);
k3 = f(mid,y[i-1]+h/2.0*k2);
k4 = f(x[i],y[i-1]+h*k3);
y[i] = y[i-1] + h/6.0*(k1 + 2*k2 + 2*k3 + k4);
}
for(int i=4;i<=maxn;i++) //Ñǵ±Ä·Ë¹Ô¤±¨-УÕýϵͳ
{
y[i] = y[i-1] + h/24.0 * (
+ 55.0 * f(x[i-1],y[i-1])
- 59.0 * f(x[i-2],y[i-2])
+ 37.0 * f(x[i-3],y[i-3])
- 9.0 * f(x[i-4],y[i-4])
);
y[i] = y[i-1] + h/24.0 * (
+ 9.0 * f(x[i],y[i])
+ 19.0 * f(x[i-1],y[i-1])
- 5.0 * f(x[i-2],y[i-2])
+ f(x[i-3],y[i-3])
);
}
for(int i=1;i<=maxn;i++)
{
cout<<x[i]<<" | ";
printf("%.6lf\n",y[i]);
}
return ;
}
void init()
{
double h = 1.0/maxn;
x[0]=0.0;
y[0]=1.0;
for(int i=1;i<=maxn;i++)
{
x[i] = x[i-1] + h;
}
return ;
}
int main()
{
init();
start();
getchar();
return 0;
}