C言語関係掲示板

過去ログ

No.1009 d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム

[戻る] [ホームページ]
No.1056

d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---初心者です(2004/01/20 19:35:04)


本調べて写したんですが間違っている個所があるそうです。コンパイラできません・・・教えてください。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double euler( double (*)(double,double),double,double,double );この行の意味がわかりません!?eulerとは何ですか?
double func (double,double);
double tfunc (double,double);この行のtfuncにする理由が?

void main ()
{
double h,x,x0,xn,y;
int i,n ;
printf("\n** d^2y/dx^2+dy/dx+8y=0 **\n");
printf("\n X の初期値 X0 =");
scanf("%le",&x0);
printf("\n Y の初期値 Y0 =");
scanf("%le",&y);
printf("\n X の初期値 XN =");
scanf("%le",&xn);
if( xn <= x0) {
printf("\n* X の指定エラー\n");
exit(1);
}

printf("\n (X0,XN) の分割数 N =");
scanf("%d",&n);
if( n < 1) {
printf("\n* N の指定エラー\n");
exit(1);
}

h = ( xn -x0 ) / n ;

printf( "\n%15s%20s%20s\n\n","X","Y","真の値" );
for (i=0 ; i < n ; i++){
x = x0 + i * h ;
printf( "%20.8e%20.10e%20.10e\n",x,y,tfunc( x ) );
y = euler(func, x, y, h );
}

printf( "%20.8e%20.10e%20.10e\n",xn,y,tfunc( xn ) );

}

double euler(double (*f)(double,double),double x, double y,double h)
/*
*オイラー法
*/
{return ( y + (*f)(x, y ) * h);
}
double func (double x,double y)
/*
* Y' = F(X,Y)を与える関数(例)
*/
{
return (y + sin( x ) ) ;
}

double tfunc( double x )
/* 上記例の真の解 */
{
return ( exp(x) - (sin(x) + cos( x )) * 0.5) ;
}

No.1057

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---たか(2004/01/20 20:06:45)


一応コンパイルできるようにしました。tfunc()のプロトタイプ宣言が
違っていたり、関数中に全角スペースが入っていたりでコンパイルでき
ないのを直しました。

でも出力結果が思わしくないですね。そちらで追試してみて下さい。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double euler( double (*)(double,double),double,double,double ); /* この行の意味がわかりません!?eulerとは何ですか? */
double func (double,double);
double tfunc (double); /* この行のtfuncにする理由が? */

int main(void)
{
  double h,x,x0,xn,y;
  int i,n ;
  printf("\n** d^2y/dx^2+dy/dx+8y=0 **\n");
  printf("\n X の初期値 X0 =");
  scanf("%le",&x0);
  printf("\n Y の初期値 Y0 =");
  scanf("%le",&y);
  printf("\n X の初期値 XN =");
  scanf("%le",&xn);
  if( xn <= x0) {
    printf("\n* X の指定エラー\n");
    exit(1);
  }

  printf("\n (X0,XN) の分割数 N =");
  scanf("%d",&n);
  if( n < 1) {
    printf("\n* N の指定エラー\n");
    exit(1);
  }

  h = ( xn -x0 ) / n ;

  printf( "\n%15s%20s%20s\n\n","X","Y","真の値");
  for (i=0 ; i < n ; i++){
    x = x0 + i * h ;
    printf( "%20.8e%20.10e%20.10e\n",x,y,tfunc( x ));
    y = euler(func, x, y, h );
  }

  printf( "%20.8e%20.10e%20.10e\n",xn,y,tfunc( xn ));

  return 0;
}

/*
 * オイラー法
 */
double euler(double (*f)(double,double),double x, double y,double h)
{
  return ( y + (*f)(x, y ) * h);
}

/*
* Y' = F(X,Y)を与える関数(例)
*/
double func (double x,double y)
{
  return (y + sin( x ) ) ;
}

double tfunc( double x ) 
/* 上記例の真の解 */
{
  return ( exp(x) - (sin(x) + cos( x )) * 0.5) ;
}



No.1058

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---かずま(2004/01/20 20:47:30)


> でも出力結果が思わしくないですね。そちらで追試してみて下さい。

オイラー(Euler)法だから、こんなもんじゃないんですか?

x0 = 0, y0 = 0.5, xn = 1 で、分割数 n = 10, 100, 1000 で試すと、やっぱり
分割数を増やすと、y は真の値に近くなるなあと実感できますが。

No.1061

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---たか(2004/01/20 21:33:17)


y''+y'+8y=0ですから2階線形同次微分方程式であり、この一般解は
exp(-0.5 * x) * (A * cos(sqrt(31) / 2 * x) + B * sin(sqrt(31) / 2 * x));

となり、AとBを決定する必要からyの初期値が2個必要だと思ったのですが。もちろんyの配列も2次元配列が必要です。

このプログラム自体は1階専用だと思います。

修正オイラー法はここを参照
して下さい。

No.1063

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---たか(2004/01/20 22:19:35)


理屈ばっかり言っていても始まりませんから、実際にプログラムを示し
ます。初期値x=1,y=1であっても、y'の初期値を1とか2とか変化させると
その後のyの挙動が変化するのがおわかりになるかと思います。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define DIVN 1000
#define M 2

void euler(double [], double [][M], double, int, int);
void euler_sub(double, double [], double []);

int main(void)
{
  double h, x[DIVN], y[DIVN][M];
  int i, n;

  printf("\n** d^2y/dx^2+dy/dx+8y=0 **\n");
  printf("X の初期値 X0 =");
  scanf("%le", &x[0]);
  printf("Y の初期値 Y0 =");
  scanf("%le", &y[0][0]);
  printf("Y' の初期値 Y1 =");
  scanf("%le", &y[0][1]);
  printf("刻み値 N =");
  scanf("%d", &n);
  printf("進み幅 H =");
  scanf("%le", &h);

  euler(x, y, h, n - 1, M);
  printf("\%9s%17s%17s\n\n","X","Y","Y'");
  for (i = 0; i < n; i++)
    printf("%17.8e%17.8e%17.8e\n", x[i], y[i][0], y[i][1]);

  return 0;
}

/*
 * オイラー法
 */
void euler(double x[], double y[][M], double h, int n, int m)
{
  int i, k;
  double f[DIVN];
  
  for (k = 0; k <= n; k++) {
    x[k] = x[0] + k * h;
    euler_sub(x[k], y[k], f);
    for (i = 0; i < m; i++)
      y[k + 1][i] = y[k][i] + h * f[i];
  }
}

void euler_sub(double x, double y[], double f[])
{
  f[0] = y[1];
  f[1] = -y[1] - 8 * y[0];
}


No.1064

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---かずま(2004/01/20 22:35:25)


> y''+y'+8y=0ですから2階線形同次微分方程式であり、この一般解は

失礼しました。
プログラムだけを見て、y' = y + sin(x) だけを考えていました。

No.1065

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---たか(2004/01/20 23:02:51)


>> y''+y'+8y=0ですから2階線形同次微分方程式であり、この一般解は
>
>失礼しました。
>プログラムだけを見て、y' = y + sin(x) だけを考えていました。

かずま様は最初のプログラムを一階微分方程式だと捉えられておられた
のですね。それでしたら間違っていません。こちこらそ失礼致しました。
ただ、タイトルが二階になっておりましたのでどう答えたものかと迷って
おりました。

おそらくご質問者は「このプログラムを二階微分方程式に適用するには
どうすればいいか」と質問されたのかと思っていました。私もオイラー
法を初めて使った時同じ落とし穴にはまってしまいましたからネ。

No.1059

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---初心者です(2004/01/20 21:18:46)


修正オイラー法のプログラム教えてください。探してるんですが・・・

No.1060

Re:d^2y/dx^2+dy/dx+8y=0をオイラー法で解くプログラム
投稿者---初心者です(2004/01/20 21:23:02)


あったかさん、かずまさん、指摘ありがとうございました。まだ、プログラムを作る事が出来ないので本当に困ってました。読むのでやっとですが、それでもまだ・・・あと、出来れば、このオイラー法の結果をグラフィックでグラフ表示をしたいのですが・・・chinouglを使っています。