<12回目課題解答>
//第12回 微分方程式の数値演算(1) 課題1
#include <stdio.h>
#include <math.h>

double func(double t,  double x){
double  a = 0.1; //[1/sec]
double b = 0.02; //[1/m]
double g =  9.807; //[m/sec2]

return -b*x*x - a*x + g;
}

double rkm(double (*fnc)(double,  double), double t, double x, double h){ //ルンゲクッタ法
double ck0, ck1, ck2, ck3;
ck0=(*fnc)(t,  x)*h;
ck1=(*fnc)(t+h*0.5, x+ck0*0.5)*h;
ck2=(*fnc)(t+h*0.5, x+ck1*0.5)*h; 
ck3=(*fnc)(t+h, x+ck2)*h; 
return (x+(ck0+(ck1+ck2)*2.0+ck3)/6.0);
}

double rkgm(double (*fnc)(double, double),  double t, double x, double h, double *q){ //ルンゲクッタ・ジル法
static double p1=0.2928932188134524,  p2=1.70710678118547;
double ck0, ck1, ck2, ck3;
double q1, q2, q3; 
double r1, r2, r3, r4;
double tt,  x1, x2, x3;

ck0=(*fnc)(t,x)*h; 
r1=ck0*0.5-*q;
x1=x+r1;
q1=*q+r1*3.0-ck0*0.5;
tt=t+h *0.5;
ck1=(*fnc)(tt ,x1)*h;
r2=(ck1-q1 )*p1;
x2=x1+ r2;
q2=q1+r2*3.0 -ck1*p1;
ck2=(*fnc )(tt,x2)*h;
r3=(ck2-q2 )*p2;
x3=x2+r3;
q3=q2+r3*3.0 -ck2*p2;
tt=t+h; 
ck3=(*fnc)( tt,x3)*h;
r4=(ck3-q3-q3 )/6.0;
*q=q3 +r4*3.0-ck3*0.5;

return (x3+r4);
}

double mlnm(double (*fnc) (double, double), double df[ ], double t, double x[], double h, double eps){ //ミルンの方法
double mlnm, ff , px;
px=x[0]+((df[3]+df[1])*2.0-df[2])*h*4.0/3.0;
while(1){ 
ff=(*fnc)(t, px); 
mlnm=x[2]+(ff+df[3]*4.0+df[2])*h/3.0; 
if(fabs(px-mlnm)< =eps){
return mlnm; 
} 
px=mlnm;
} 
}

double  admsm(double (*fnc)(double, double), double df[ ], double t, double x[], double h, double eps){ //アダムス法
double admsm,  ff, hd, px;
hd= h/24.0;
px=x[3]+(df[3]*55.0-df[2]*59.0+df [1]*37.0-df[0]*9.0)*hd;
while(1){ 
ff=( *fnc)(t, px);
admsm=x[3]+( ff*9.0+df[3]*19.0-df[2]*5.0+df[1])*hd;
if(fabs(px-admsm)  <=eps){
return  admsm;
}
px = admsm ;
}
}

void main(){
double eps = 0.00001, h = 0.1, xx = 10.0,  q = 0;
double x[5] = {0}, df[5]  = {0};
double (*f1)(double,double);
double rk =  0, rkg = 0, mln = 0, adms = 0;
int j  = 0;
double t =  0, t0 = 0;

f1 =  &func;

printf("ルンゲクッタ法\nt,v\n" );
for(double i = 0; i  <= xx; i += h){
printf("%f,%f\n", i,  rk);
rk = rkm(f1,  i, rk, h);
if(j <= 3){ 
x[j] =  rk;
df[j] = func( i, x[j]);
}
j++;
}
printf("\n");

printf("ルンゲクッタ・ギル法\nt,v\n");
for(double i =  0; i <= xx; i += h){
printf("%f,%f\n", i, rkg);
rkg = rkgm(f1 , i, rkg, h, &q);
}
printf("\n");

printf("ミルン法\nt,v\n0,%f\n",mln);
j = 0 ;
for(double i  = 0; i <= 3*h; i += h){
printf("%f,%f\n",  i+h, x[j]);
j++;
}
for(double i  = 3*h; i < xx; i += h){
mln = mlnm(f1, df, i, x, h, eps);
x[4] =  mln;
df[4] =  func(i, mln);
for(int k = 0; k <= 3; k++){
x[k] = x[k+1];
df[k] = df[k+1];
}
x[0] = x[1];
x[1] = x[2];
x[2] = x[3];
x[3] = mln;
df[0] = df[1];
df[1] = df[2];
df[2] = df[3];
df[3] = func(i, x[3]);
printf("%f,%f\n", i+h, mln);
}
printf("\n");

printf("アダムス法\nt,v\n");
j = 0;
adms = 0;
x[0] = 0; 
for(int i=0; i<=3; i++){
t=t0+i*h;
df[i]=func(t, x[i]);
if(i<3) {
x[i+1]=rkm(f1, t, x[i], h);
}
printf("%f,%f\n", t, x[i]);
}
for(double  i = 3*h; i <= xx; i += h){
adms =  admsm(f1, df, i, x, h, eps);
x[4] = adms;
df[4] = func(i, adms);
for(int  k = 0; k <= 3; k++){
x[k] = x[k+1];
df[k ] = df[k+1];
}
printf("%f,%f\n", i , adms);
}
printf("\n");
}

//第12回 微分方程式の数値演算(1) 課題2
#include <stdio.h>
#include <math.h>

double f(double f, double x, double z){ //dx/dt = z
return z;
}

double g(double f, double x, double z){ //dz/dt = -(c/m)z - (k/m) x + (u/m)
double cm =  0.02;
double km = 0.1 ;
double um = 1; 

return -cm*z - km*x + um; 
}

void rkm(double (*f1)(double, double, double), double(*f2)(double, double, double), double t, double x, double z, double h, double *ff, double *ll){ //ルンゲクッタ法(2階微分)
double ck0, ck1, ck2, ck3, cl0, cl1, cl2, cl3; 
ck0=(*f1)(t, x, z)*h; 
cl0=(*f2)(t, x, z)*h;
ck1=(*f1)(t+h*0.5,  x+ck0*0.5, z+cl0*0.5)*h;
cl1=(*f2)(t+h*0.5, x+ck0*0.5, z+cl0*0.5)*h;
ck2=(*f1)(t+h*0.5, x+ck1*0.5, z+cl1*0.5)*h;
cl2=(*f2)(t+h*0.5, x+ck1*0.5, z+cl1*0.5)*h;
ck3=(*f1)(t+h,  x+ck2, z+cl2)*h;
cl3=(*f2)(t+h, x+ck2, z+cl2)*h;
*ff = (x+(ck0+(ck1+ck2)*2.0+ck3)/6.0);
*ll = (z+(cl0+(cl1+cl2)*2.0+cl3)/6.0);
}

void main( ){
double x = 0.05;
double z = 1;
double h = 0.1;
double t = 0, t0 = 0, tmax = 100;
double ff = 0, ll = 0;

printf("t,x,dx/dt\n");
for(int i = 0; i <= tmax/h; i++){
t = t0 + (double)i * h;
rkm(f, g, t, x, z, h, &ff, &ll);
if(i%10 == 0) printf("%f, %f, %f\n", t, ff, ll);
x =  ff;
z = ll;
}

}