• ベストアンサー

数値解析に関する質問です。

/*kadai8 Euler’s Method for Ordinary Differential Equation */ #include <stdio.h> void euler(double *, double *); main () { int i; double v,t,tt,dt[5]; dt[0] = 2; dt[1] = 1; dt[2] = 0.1; dt[3] = 0.01; dt[4] = 0.001; printf("Program of Euler`s Method 1\n"); printf("-----------------------------------------\n"); tt = 50.0/9.80665; printf("Theoretical Solution : %lfs\n",tt); for(i=0;i<=4;i++){ printf("--------------------------------\n"); printf("Step Size : %lf s\n",dt[i]); v=50.0; t=0.0; while(v>0) { euler(&v,&dt[i]); t=t+dt[i]; } printf("Numerical Solution : %lf s\n",t); printf("Error : %lf s\n",t-tt); } return(0); } /*--------------*/ void euler(double *v,double *dt) { *v=*v + (*dt )*(-9.80665); } 以上のプログラムで関数eulerの引数にポインタがついているのはなぜか,またポインタを使用しない方法はないか?また、オイラー法より精度の高い解法はありますか? よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Interest
  • ベストアンサー率31% (207/659)
回答No.1

Q1: 関数eulerの引数にポインタがついているのはなぜか A1: 関数euler内部での計算結果を呼び出し元に返すため。もっとも、dt は関数 euler の中で更新されないのでポインタである必要はない。 Q2: またポインタを使用しない方法はないか? A2: ある。例えば関数 eulerを次のようにする。 double euler(double v, double dt) {  return v + dt * (-9.80665); } Q3: オイラー法より精度の高い解法はありますか? A3: ある。定番はルンゲ=クッタ法。数値計算法の教科書には常微分方程式の解法として必ずルンゲ=クッタ法の説明が書かれている。

その他の回答 (1)

回答No.2

ポインタを使わなくても大丈夫ですよ。 ただ、オーバーヘッドががあります。数値解析では無駄なオーバーヘッドはできる限り排除したいのでこういう形になっているのでは? 数値解析は学生時代にやっただけでかなり忘れてしまっていますが、ルンゲクッタ法とかって違いましたっけ?

関連するQ&A

  • 数値解析に関する質問です

    以下のプログラムにおいて 1) 初項の絶対値が大きい方の式を選んで消去する理由は何故か? 2)2元1次連立方程式の解が得られないデータ(例えば,1 2 3と2 4 6)を入力した場合,エラーを表示するようにするにはどうすればよいか? 教えてください。 よろしくお願いします。 #include <stdio.h> #include<math.h> //-------------------------------- void inputdata(double [2][3]); void calsol(double [2][3], double [2]); void elimination(double [2][3], double [2][3]); void outputdata(double [2]); void checksol(double [2][3], double [2]); //--------------------------------- main() { double c[2][3], x[2]; printf("Program of Gaussian elimination \n"); inputdata(c); calsol(c, x); outputdata(x); checksol(c, x); return(0); } //----------------------------- void inputdata(double c[2][3]) { printf("----------------------\n"); printf("Input Data\n"); printf("(a0*x0 + a1*x1 = a2)\n"); printf("\n"); printf("Equation 1\n"); printf("Input a0 a1 a2\n"); scanf("%lf%lf%lf" , &c[0][0], &c[0][1], &c[0][2]); printf("Equation 2\n"); printf("Input b0 b1 b2\n"); scanf("%lf%lf%lf", &c[1][0], &c[1][1], &c[1][2]); } //----------------------------- void calsol(double c[2][3], double x[2]){ double cc[2][3]; elimination(c, cc); x[1]=cc[1][2]; x[0]=cc[0][2]-cc[0][1]*x[1]; } //----------------------------- void elimination(double c2[2][3],double cc[2][3]) { int imax; double c1[3]; if(fabs(c2[0][0])>fabs(c2[1][0])){ imax = 0; } else{ imax = 1; } cc[0][0] = 1; if (imax == 0){ cc[0][1]= c2[imax][1]/c2[imax][0]; cc[0][2]=c2[imax][2]/c2[imax][0]; } else{ cc[0][1]=c2[1][1]/c2[1][0]; cc[0][2]=c2[1][2]/c2[1][0]; c1[0]=0; c1[1]=c2[0][1]-(cc[0][1]*c2[0][0]); c1[2]=c2[0][2]-(cc[0][2]*c2[0][0]); } cc[1][0]=c1[0]; cc[1][1]=1; cc[1][2]=c1[2]/c1[1]; } //----------------------------- void outputdata(double x[2]){ printf("--------\n"); printf("Solutions\n"); printf("x0=%14.6e\n", x[0]); printf("x1=%14.6e\n", x[1]); } //----------------------------- void checksol(double check [2][3],double x[2]) { double crt, clt; int ie; printf("---------\n"); printf("Check Solutions\n"); printf("Left Term Right Term\n"); for(ie=0; ie<=1; ie++) { clt = check[ie][0]*x[0] + check[ie][1]*x[1]; crt = check[ie][2]; printf("%14.6e %14.6e\n", clt,crt); } } 実行結果 Program of Gaussian elimination ---------------------- Input Data (a0*x0 + a1*x1 = a2) Equation 1 Input a0 a1 a2 2 3 13 Equation 2 Input b0 b1 b2 4 8 32 -------- Solutions x0= 2.000000e+00 x1= 3.000000e+00 --------- Check Solutions Left Term Right Term 1.300000e+01 1.300000e+01 3.200000e+01 3.200000e+01

  • 数値解析に関する質問です。

    数値解析に関する質問です。 以下のプログラムでは、4元1次連立方程式のデータは、cとcheckの2つの配列に入力される。この理由を教えてください。また、1つの配列に入力して済ませる方法を教えてください。 よろしくお願いします。 /*kadai 13 Gaussian Elimination Method for System of Linear Equations*/ #include <stdio.h> #include<math.h> /*---------------------------*/ void inputdata(double[4][5],double [4][5]); void calsol(double [4][5],double [4]); void elimination(double [4][5], double [4][5]); void pivot(int *, double [4][5], int *); void outputdata(double [4]); void checksol(double [4][5],double [4]); /*---------------------------*/ main(){ double c[4][5], check[4][5],x[4]; /*---------------------------*/ printf("Program of Gaussian Elimination Method 3\n"); /*---------------------------*/ inputdata(c, check); /*---------------------------*/ calsol(c,x); /*---------------------------*/ outputdata(x); /*---------------------------*/ checksol(check, x); /*---------------------------*/ return(0); } /*---------------------------*/ /* Function inputdata */ /*--------------------------*/ void inputdata(double c[4][5],double check[4][5]){ int ie,ic; printf("-----\n"); printf("Input Data\n"); printf("(a0*x0 + a1*x1 + a2*x2 +a3*x3 = a4)\n"); printf("\n"); for(ie=0; ie<=3; ie++){ printf("Equation %d\n",ie); printf("Input a0 a1 a2 a3 a4\n"); for (ic=0; ic<=4; ic++){ scanf("%lf",&c[ie][ic]); check[ie][ic] = c[ie][ic]; } } } /*---------------------------*/ /* Functiom calsol */ /*---------------------------*/ void calsol(double c[4][5],double x[4]){ double cc[4][5]; elimination(c, cc); x[3]=cc[3][4]; x[2]=cc[2][4]-cc[2][3]*x[3]; x[1]=cc[1][4]-cc[1][3]*x[3]-cc[1][2]*x[2]; x[0]=cc[0][4]-cc[0][3]*x[3]-cc[0][2]*x[2]-cc[0][1]*x[1]; } /*---------------------------*/ /*Function elimination */ /*---------------------------*/ void elimination(double c[4][5],double cc[4][5]){ int ie,ic,ienew,imax,eli; eli = 0; while(eli<4){ pivot(&eli,c,&imax); cc[eli][eli] = 1; for(ie=eli+1;ie<=4;ie++){ cc[eli][ie]=c[imax][ie]/c[imax][eli]; } ienew= 0; for(ic=0;ic<=3-eli;ic++){ if(ie != imax){ for(ie=eli+1;ie<=4;ie++){ c[ienew][ie]=c[ic][ie]-cc[eli][ie]*c[ic][eli]; } ienew = ienew + 1; } } eli = eli +1; } } /*---------------------------*/ /*Function pivot */ /*---------------------------*/ void pivot(int *eli,double c[4][5],int *imax){ int ie; double cmax; cmax=0; for(ie=0;ie<=4-*eli;ie++){ if(fabs(c[ie][*eli])>cmax){ cmax=fabs(c[ie][*eli]); *imax=ie; } } } /*---------------------------*/ /*Function outputdata */ /*---------------------------*/ void outputdata(double x[4]){ int i; printf("------\n"); printf("Solutions\n"); for(i=0;i<=3;i++){ printf("x%d=%14.6e\n",i,x[i]); } } /*---------------------------*/ /*Function checksol*/ /*---------------------------*/ void checksol(double check[4][5],double x[4]){ double crt,clt; int ie,ic; printf("-------\n"); printf("Check Solutions\n"); printf("Left Term Right Term\n"); for(ie=0;ie<=3;ie++){ clt = 0; for(ic =0;ic<=3;ic++){ clt = clt + check[ie][ic]*x[ic]; } crt = check[ie][4]; printf("%14.6e %14.6e\n",clt,crt); } }

  • 数値解析に関する質問です

    以下のプログラムでは、関数pivotは,3つの引数を利用しているが,これを2つに減らす方法はないか? 教えてください。よろしくお願いします。 /*Gaussian Elimination*/ #include <stdio.h> #include <math.h> /*--------------*/ void inputdata(double [3][4]); void calsol(double [3][4],double [3]); void elimination(double[3][4],double[3][4]); void pivot(int *, double [3][4],int *); void outputdata(double [3]); void checksol(double [3][4], double [3]); /*--------------*/ main(){ double c[3][4], x[3]; /*-----------------------*/ printf("Program of Gauss Elimination\n"); /*-----------------------*/ inputdata(c); /*-----------------------*/ calsol(c,x); /*-----------------------*/ outputdata(x); /*-----------------------*/ checksol(c,x); /*-----------------------*/ return(0); } /*-----------------------*/ void inputdata(double c[3][4]){ int ie,ic; printf("------\n"); printf("Input Data\n"); printf("(a0*x0 + a1*x1 +a2*x2 = a3)\n"); printf("\n"); for(ie=0; ie<=2; ie++){ printf("Equation %d\n",ie); printf("Input a0 a1 a2 a3\n"); for(ic=0;ic<=3;ic++){ scanf("%lf", &c[ie][ic]); } } } /*-----------------------*/ void calsol(double c[3][4], double x[3]){   double cc[3][4]; elimination(c,cc); x[2]=cc[2][3]; x[1]=cc[1][3]-cc[1][2]*x[2]; x[0]=cc[0][3]-cc[0][2]*x[2]-cc[0][1]*x[1]; } /*-----------------------*/ void elimination(double c3[3][4], double cc[3][4]){ int ie,imax,eli; double c2[3][4],c1[3][4]; eli = 0; pivot (&eli,c3,&imax); cc[0][0]=1; cc[0][1]=c3[imax][1]/c3[imax][0]; cc[0][2]=c3[imax][2]/c3[imax][0]; cc[0][3]=c3[imax][3]/c3[imax][0]; for(ie=0;ie<=2;ie++){ if(ie != imax){ c2[ie][0]=0; c2[ie][1]=c3[ie][1]-cc[0][1]*c3[ie][0]; c2[ie][2]=c3[ie][2]-cc[0][2]*c3[ie][0]; c2[ie][3]=c3[ie][3]-cc[0][3]*c3[ie][0]; } } eli = 1; pivot(&eli,c2,&imax); cc[1][1]=1; cc[1][2]=c2[imax][2]/c2[imax][1]; cc[1][3]=c2[imax][3]/c2[imax][1];   for(ie=0;ie<=1;ie++){ if(ie !=imax){ c1[0][2]=c2[ie][2]-cc[1][2]*c2[ie][1]; c1[0][3]=c2[ie][3]-cc[1][3]*c2[ie][1]; } } cc[2][2]=1; cc[2][3]=c1[0][3]/c1[0][2]; } /*-----------------------*/ void pivot(int *eli,double c[3][4],int *imax){ int ie; double cmax; if(*eli ==0){ cmax=0; for(ie=0;ie<=2;ie++){ if(fabs(c[ie][0])>cmax){ cmax=c[ie][0]; *imax=ie; } } } else{ cmax=0; for(ie=0;ie<=1;ie++){ if(fabs(c[ie][1])>cmax){ cmax=c[ie][1]; *imax=ie; } } } } /*-----------------------*/ void outputdata(double x[3]){ int i; printf("------\n"); printf("Solutions\n"); for(i=0;i<=2;i++){ printf("x%d=%14.6e\n",i,x[i]); } } /*-----------------------*/ void checksol(double check[3][4],double x[3]){ double crt,clt; int ie,ic; printf("------\n"); printf("Check Solutions\n"); printf("Left Term Right Term\n"); for(ie =0;ie<=2;ie++){ clt =0 ; for(ic=0;ic<=2;ic++){ clt = clt + check[ie][ic]*x[ic]; } crt = check[ie][3]; printf("%14.6e%14.6e\n",clt,crt); } }

  • 数値の連続入力終了条件について

    C言語初心者です。よろしくお願いします。 早速質問なのですが、while文を使ったscanf()関数による数値連続入力で、 ◎1---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;      while(scanf("%lf",&dt) !=EOF){   sum=sum+dt; }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎1のようにすれば、Ctrl+ZでEOFが返されたら終了とわかるのですが、今度は「0」が入力されたら処理を終了するというプログラムで、 ◎2---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;      while(scanf("%lf",&dt) !=0.0){   sum=sum+dt; }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎2のようにすると「0」が入力されても、終了せず、以下に示す◎3のように、しないと終了出来ません。 ◎3---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;          scanf("%lf",&dt);      while(dt!=0.0){   sum=sum+dt; scanf("%lf",&dt); }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎2で何故、◎1のように出来ず、◎3のようなscanf()を1回目、2回目と判定を入れなければならないか教えて下さい。

  • C言語のポインタのプログラムについての質問です。

    C言語のポインタについて質問です。 nこの配列データaを受け取り、それらの値をもとに、2つのデータを引数で受け取って交換する関数void swap(double *a,*b)を用いることにより最終的に降順に並べ替えて出力したのち、それらを平均(average)と標準偏差(standard deviation)を引数で受け渡す関数 void calc_ave_stddev(int n,double a[],double *ave,double*stddev)を利用して出力されるプログラムを教えてほしいです。 main関数内での書式は printf("enter n:"); scanf("%d,&n"); for(i=0;i<n;i++){ printf("enter a[%d]:",i); scanf("%lf"&a[i]); } main関数での結果の出力は、 for(i=0;i<n;i++){ printf("a[%d]=%lf\n",a[i]); } printf("ave=%lf stddev=%lf\n",ave,stddev); です。

  • C++についての質問です

    プログラミング初心者です 以下の通りに正方行列の積を求めるプログラムを作成したのですが、うまくいきません。 #include<stdio.h> #define DTM 20 void InputMatrix(double[][DTM], int, char); void PrintMatrix(double[][DTM], int, char); void MatrixMulti(double[][DTM], double[][DTM], double[][DTM], int); int main(void) { double matrixA[DTM][DTM]; double matrixB[DTM][DTM]; double matrixC[DTM][DTM]; int n; printf("正方行列の積を求めるプログラムです\n"); printf("正方行列の次元を入れてください(<=20):"); scanf_s("%d", &n); InputMatrix(matrixA, n, 'A'); InputMatrix(matrixB, n, 'B'); MatrixMulti(matrixA, matrixB, matrixC, n); printf("\n行列 C =A×B\n"); PrintMatrix(matrixC, n, 'C'); return 0; } void InputMatrix(double a[][DTM], int n, char ch) { int i, j; printf("行列 %cの入力\n", ch); for (i = 0; i < n;i++) { for (j = 0;j < n;j++) { printf("%c[%d][%d] =", ch, i + 1, j + 1); scanf_s("%lf", &a[i][j]); } } } void PrintMatrix(double a[][DTM], int n, char ch) { int i, j; printf("行列 %c の出力\n", ch); for (i = 0;i < n;i++) { for (j = 0;j < n;j++) { printf("%5.2f\t", a[i][j]); } printf("\n"); } } void MatrixMulti(double a[][DTM], double b[][DTM], double c[][DTM], int n) { int i, j, k; for (i = 0;i < n;i++) { for (j = 0;j < n;j++) { c[i][j] = 0; for (k = 0;k < n;k++) { c[i][j] =a[i][k] * b[k][j]; } printf("%5.2f\t",c[i][j]); } printf("\n"); } }

  • プログラミングの変数について質問です。

    プログラミングの変数について質問です。 次のプログラミングは自分で書いたプログラムの一部です。 void inputmonster(int x[][3], struct monster monster) { int i, s, t, m, n; for(t = 0; t < 2; t++){ s = 0; while (s < 1){ printf("player%dは好きなモンスターを3つ選んでください\n\n", t+1); for (i = 0; i<3; i++){ printf("%d体目を選んでください。\n\n", i+1); for(m = 0; m < 5; m++) printf("%d, %s\n", m+1, monster[m].name); scanf("%d", &x[t][i]); printf("%d体目 : %s\n\n", i+1, monster[x[t][i]-1].name); } printf("これでよろしいですか?\n"); for(i = 0; i<3; i++) printf("%d体目 : %s ", i+1, monster[x[t][i]-1].name); printf("1、はい 2、いいえ\n"); scanf("%d", &n); if(n == 1) s = 1; else s = 0; } } } これをコンパイルすると次のようなエラーが表示されます。 monsterbattle.c: 関数 ‘inputmonster’ 内: monsterbattle.c:497:63: エラー: 添字が付けられた値が、配列、ポインタまたはベクト ルではありません for(m = 0; m < 5; m++) printf("%d, %s\n", m+1, monster[m].name); ^ monsterbattle.c:499:45: エラー: 添字が付けられた値が、配列、ポインタまたはベクト ルではありません printf("%d体目 : %s\n\n", i+1, monster[x[t][i]-1].name); ^ monsterbattle.c:503:68: エラー: 添字が付けられた値が、配列、ポインタまたはベクト ルではありません for(i = 0; i<3; i++) printf("%d体目 : %s ", i+1, monster[x[t][i]-1].na me); どのように改変すればこのようなエラーを表示しないようにできるのでしょうか? 基本的な質問ではあると思いますが、是非教えていただけるとありがたいです。 よろしくお願いします。

  • for文内でscanf関数により配列に数値を格納することについて

    プログラミング初心者です。 よろしくお願いします。 ◎1------------------------------------ #include<stdio.h> int main(void) { int i,dt[3]; for(i=0;i<3;++i){ printf("dt[0]=%d\n",dt[0]); printf("dt[1]=%d\n",dt[1]); printf("dt[3]=%d\n",dt[3]); scanf("%d",&dt[i]); printf("i=%d\n",i); puts(""); if(dt[i]==0){ break; } } printf("dt[0]=%d\n",dt[0]); printf("dt[1]=%d\n",dt[1]); printf("dt[2]=%d\n",dt[2]); printf("dt[3]=%d\n",dt[3]); printf("i=%d\n",i); puts(""); i=1; while(1){ printf("%d ",i); if(1000<i){ break; } i*=2; } puts(""); return 0; } ---------------------------------------- ◎2------------------------------------ #include<stdio.h> int main(void) { int i,dt[2]; for(i=0;i<3;++i){ printf("dt[0]=%d\n",dt[0]); printf("dt[1]=%d\n",dt[1]); printf("dt[2]=%d\n",dt[2]); scanf("%d",&dt[i]); printf("i=%d\n",i); puts(""); if(dt[i]==0){ break; } } printf("dt[0]=%d\n",dt[0]); printf("dt[1]=%d\n",dt[1]); printf("dt[2]=%d\n",dt[2]); printf("i=%d\n",i); puts(""); i=1; while(1){ printf("%d ",i); if(1000<i){ break; } i*=2; } puts(""); return 0; } ---------------------------------------- 以上2つのプログラムについて疑問があります。 まず◎1については、あえて添え字のdt[3]の値を見てみようと思ったら、iの値が入っているとわかりました。 しかし、何故添え字の番号の配列にiの値が入っているのかがわかりません。 次に◎2ですが、3回目のループで、添え字の番号の配列自身に入力した数値を格納すると、iと添え字番号配列に入力した数値が入っていました。 何故このようになっているのか疑問です。 以上のような疑問があります。 添え字の番号の配列とiが何か関連があるようですがいまいちわかりません。 教えていただけると嬉しいです。

  • 大学のC言語の課題で

    ルンゲクッタ法を用いたバネの単振動を解析する課題をやっています。以下の部分まで作ったのですが、 どうしても最後のほうがわかりません。 関数fとf2のreturn やメイン関数を変更すればいいとおもうのですが、どうやっても満足な結果が得られません。どなたか詳しい方教えてもらえない? #include<stdio.h> #include<math.h> double f(double t,double y1) { return y1; } double f2(double t2,double y2) { double w=5.0,k=0.5; return -w*w*f(t2,y2)-2.0*k*y2; } int main(void) { int count,bunkatu,npr; double t_0,T; double k1,k2,k3,k4; double y,t,dt,dt_2,dt_6; t_0 = 0.0; T=10.0; bunkatu=2000; npr=1000; y=1.0; printf("\n# [t_0,T]=[%6.4lf,%6.4lf] N=%d\n",t_0,T,bunkatu); t=t_0; dt=(T-t_0)/(double)bunkatu; dt_2=dt/2.0; dt_6=dt/6.0; for(count=0;count <=bunkatu;count++) { if(count %(bunkatu/npr)==0) printf("\n %5.2lf %10.5f",t,y); k1=f2(t,y); k2=f(t+dt_2,y+k1*dt_2); k3=f(t+dt_2,y+k2*dt_2); k4=f(t+dt,y+k3*dt); y+=(k1+2.0*k2+2.0*k3+k4)*dt_6; t+=dt; } printf("\n"); return 0; }

  • 物体が落ちるまで

    初速度v、打ち上げ角度rでうち上がってから落ちてくるまでの 物体の位置を表示するというものなのですが とりあえず n秒後の物体の高さをhとしたときhを出す関数を 作って見たのですがうまくできません。見てもらえないでしょうか。 #include <stdio.h> #include <math.h> void input(double *v, double *r, double *n); void solve(double v, double r, double n); int main(void) { double v, r, n; input(&v, &r, &n); solve(v, r, n); return 0; } void input(double *v, double *r, double *n) { puts("物体を打ち上げ角r、初速度vで打ち上げた時、n秒後の高さhを求めます。"); puts("初期値v, r, nを入力してください"); printf("v="), scanf("%lf", v); printf("r="), scanf("%lf", r); printf("n="), scanf("%lf", n); putchar('\n'); } void solve(double v, double r, double n) { double w = sin(r); printf("sin r は = %f です。\n",w);<ーーーここでsin r がうまく求まりません。 printf("したがって求めたいn秒後の物体の高さhは、\n"); double h = v * w * n - 5 * n * n; printf("h=%f\n",h); } です。重力加速度は10としています。 あと、できればこのhを以下のように表示する方法も教えて下さい。 |* | * | * | * |* お願いします。

専門家に質問してみよう