EMANの物理学 過去ログ No.7584 〜

 ● 単振動

  投稿者:ヴィダル - 2009/08/30(Sun) 15:09  No.7584 
お邪魔します。
UNIXでC言語を用いた一次の一番単純な単振動のプログラミングで苦戦しております。
どなたかご指南願います・・・ポインタと配列がどうのこうのらしいのですが、調べてみてもピンとくる説明がありません。

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

#define dt 0.01
#define tmax 50000.0

/*変数の設定*/

double f1(double t, double x, double v){
return(v);
}

double f2(double t, double x, double v){
return(-x);
}

/*アルゴリズム=ルンゲ=クッタ法=*/

int main(){

double t,x,v,j;
double k1[0],k1[1],k2[0],k2[1],k3[0],k3[1],k4[0],k4[1];

for(j=0;j<=tmax;j++){

t[j]=j*dt;

k1[0]=dt*f1(t,x,v);
k1[1]=dt*f2(t,x,v);

k2[0]=dt*f1(t+dt/2.0,x+k1[0]/2.0,v+k1[1]/2.0);
k2[1]=dt*f2(t+dt/2.0,x+k1[0]/2.0,v+k1[1]/2.0);

k3[0]=dt*f1(t+dt/2.0,x+k2[0]/2.0,v+k2[1]/2.0);
k3[1]=dt*f2(t+dt/2.0,x+k2[0]/2.0,v+k2[1]/2.0);

k4[0]=dt*f1(t+dt,x+k3[0],v+k3[1]);
k4[1]=dt*f2(t+dt,x+k3[1],v+k3[1]);

x[j+1]=x[j]+dt*(k1[0]+2.0*k2[0]+2.0*k3[0]+k4[0])/6;
v[j+1]=v[j]+dt*(k1[1]+2.0*k2[1]+2.0*k3[1]+k4[1])/6;

printf("%f %f %f\n",t,x,v);

/*初期値の設定*/

x[0]=1.0;
v[0]=0.0;

}

return 0;

}


  投稿者:EMAN - 2009/08/30(Sun) 16:35  No.7585 
 確かにおかしい。 どこからつっこもうかなぁ。

> double k1[0],k1[1],k2[0],k2[1],k3[0],k3[1],k4[0],k4[1];

ってのは配列の宣言ですから、これはまずい。 もし、

double k1[2];

と書けば、それは k1という変数名の配列を2つ使うよ、という意味になります。 つまり、k1[0] と k1[1] の二つを使えるようになります。

ところが、ここでは

double k1[0], k1[1];

のような感じになってますから、k1の配列を 0 個使うよ(つまり使わないよーん)と言った直後に、やっぱ k1 の配列を 1 個使うよーなどと言ってるようなもんです。 コンピュータに言わせれば、「どっちなんじゃい!」という感じです。
 さらにプログラム中では k1[1] とか出てきますから、「宣言した配列より多いじゃないか」というわけです。 ( k1[1]と宣言したら、一個だけ、つまり k1[0] だけしか使えないのです。)

だから、次のように直せば状況はかなり改善します。

double k1[2], k2[2], k3[2], k4[2];

 しかしこれだけの用事のために配列を使うのは感心しません。
 まぁいいや。 私はあんまり厳しいことを言うタイプではないので、初心者にとっては、とりあえず動くのが優先事項だろう、と考えてますから。 しかしとりあえず動いた後では精進を怠らないようにして下さい。

 ・・・やっぱり、安全教育の方が先なのかなぁ・・・。
 配列を宣言した以上に勝手に使うと、メモリの予想外のところをアクセスして、とんでもないことが起こる可能性もあるのです。

 さて、これだけではまだ動きませんので、また書き込みます。

  投稿者:EMAN - 2009/08/30(Sun) 16:54  No.7586 
> x[j+1]=x[j]+dt*(k1[0]+2.0*k2[0]+2.0*k3[0]+k4[0])/6;
> v[j+1]=v[j]+dt*(k1[1]+2.0*k2[1]+2.0*k3[1]+k4[1])/6;

という部分があります。
 これは x と v を配列として使っています。
 プログラムを読むと、j は 50000 まで増えますから、それ以上の容量を宣言しておかないといけません。 t も同じだけ使いますね。

> double t,x,v,j;

という宣言ではだめで、

double t[60000], x[60000], v[60000];
int j;

のような感じにしておかないと・・・。
 しかし配列を 60000 個も使用するのは異常ですね。
 こんな調子ではメモリを食いすぎます。

 ああ、どうしよう。 時間がないので、とりあえずここまで。

  投稿者:ヴィダル - 2009/08/30(Sun) 20:11  No.7589 
返信ありがとうございます。
EMANさんのアドバイスを参考にしながらもう一度考えてみます。
また要領を得ない質問をしてしまうかも知れませんが、
そのときはまたご指導のほどよろしくお願いします><