有人可以在我的代码中找到错误吗?它在特殊点中工作正常,但公差不适合该方法。我的Errorstepper很简单,所以我不认为它的问题。请帮忙。
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <iostream>
#include <string>
using namespace std;
const int q=10;
const double b=8/3;
double r;
double x,y,z;
struct delta
{
double dx;
double dy;
double dz;
};
double f1(double x , double y)
{
return (q*(y-x));
}
double f2(double x,double y, double z)
{
return ((-x)*z+r*x-y);
}
double f3(double x,double y,double z)
{
return (x*y- b*z);
}
delta calc(double x,double y,double z,double dh=0.1)
{
double k1,k2,k3,k4,m1,m2,m3,m4,p1,p2,p3,p4,dx,dy,dz,a,b,c,h;
h=dh;
k1=h*f1(x,y);
m1=h*f2(x,y,z);
p1=h*f3(x,y,z);
//h+=dh/2;
k2=h*f1((x+k1/2.),(y+m1/2.));
m2=h*f2((x+k1/2.) ,(y+m1/2.),(z+p1/2.));
p2=h*f3((x+k1/2.),(y+m1/2.),(z+p1/2.));
// h+=dh/2;
k3=h*f1((x+k2/2.),(y+m2/2.));
m3=h*f2((x+k2/2.),(y+m2/2.),(z+p2/2.));
p3=h*f3((x+k2/2.),(y+m2/2.),(z+p2/2.));
// h+=dh;
k4=h*f1((x+k3),(y+m3));
m4=h*f2((x+k3),(y+m3),(z+p3));
p4=h*f3((x+k3),(y+m3),(z+p3));
dx=(k1+2*k2+2*k3+k4)/6.;
dy=(m1+2*m2+2*m3+m4)/6.;
dz=(p1+2*p2+2*p3+p4)/6.;
a=x+dx;
b=y+dy;
c=z+dz;
delta add;
add.dx=a;
add.dy=b;
add.dz=c;
return add;
}
double Error(double x,double y ,double z, double h)
{
double xi,e,a,b,c;
delta end1=calc(x,y,z,h);
xi=end1.dx;
end1=calc(x,y,z,h/2);
a=end1.dx;
b=end1.dy;
c=end1.dz;
end1=calc(a,b,c,h/2);
e=fabs((xi-end1.dx)/15);
return e;
}
int main ()
{
double dx,dy,dz,h,ei,xi,zi,yi,e,t=0,T=0.08,a,b,c,k=0,E,h1,e1,m,E1;
int n=0;
FILE *fff;
fff=fopen("data.txt","w");
cout <<"x0=";
cin>>x;
cout<<"y0=";
cin>>y;
cout<<"z0=";
cin>>z;
cout<<"h=";
cin>>h;
cout<<"r=";
cin>>r;
cout<<"Time=";
cin>>T;
cout<<"Toleranse=";
cin>>E;
xi=x;
double hmin=0.00005;
if (E<=0.0000001)
hmin=hmin/100;
else cout<<"ok"<<endl;
E1=E/10;
do
{
e=Error(x,y,z,h);
while (e<E1 || e>E)
{
if (e<E1)
h+=hmin;
else if (e>E)
h-=hmin;
else cout<<" ok"<<endl;
e=Error(x,y,z,h);
};/*
while(e>E)
{
h=h/2;
e=Error(x,y,z,h);
};*/
xi=x;
yi=y;
zi=z;
ei=e;
delta konec1=calc(x,y,z,h);
x=end1.dx;
y=end1.dy;
z=end1.dz;
t+=h;
k+=1;
// cout<<"x="<<x<<" y= "<<y<<" z="<<z<<" Pogreshnost= "<<e<<" Time="<<t<<endl;
fprintf(fff,"%lf, %lf, %lf, %.10lf ,%lf ,%lf\n", x, y,z,e,t, h);
}
while (t<=T);
fprintf(fff,"Step = %lf",T/k);
fclose(fff);
}
答案 0 :(得分:1)
您的错误步进器,看起来很简单,正在实施一些错误的想法。
一般假设是,在最低阶中,本地错误为e=C·h^5
。以步长的一半执行两个步骤因此会产生错误
e2=2·C·(h/2)^5=C·h^5/16=e/16.
由于人们只知道计算RK4步骤的值y1=y+e
和y2=y+e2=y+e/16
,因此可以找到
y1-y2=15/16*e or e=16/15*(y1-y2) and e2=(y1-y2)/15.
假设局部错误统一且附加地转换为全局错误,则会得到e·(T/h)
的全局错误。或者解释不同,e/h
是局部误差密度,所需的全局误差E
转换为平均误差密度E/T
。因此,您必须将e
与E/T·h
进行比较,而不是将其与E
进行比较。特别是缺失的因素h
将导致步长不合适。
整个步长计算在计算上也太昂贵了。由于本地错误被发现为e=C·h^5
,并且所需的本地错误为E·h/T
,因此可能最佳步长h1
(不包括较高的高阶效果)由
C·h1^4=E/T or h1 = h*(E/(e*T))^0.25.
这个公式比几千次迭代的循环快得多,每次循环3个RK4。可以围绕该公式构建检查,以便确保新的步长确实具有该局部错误,并且步骤大小的变化不是太激进,在伪概念C代码中
fac = 1.0;
do {
h *= fac;
y1 = /* RK4 step with h */;
y2 = /* 2 RK4 steps with h/2 */;
e = 16*norm(y1-y2)/15;
fac = pow(E/(e*T), 0.25);
fac = min(20, max(0.05, fac) );
} while( fac<0.5 or 2<fac )
// advance the integration