• 締切済み

シンプソン則について

大学の課題で ∫0~5 e^(-3t) * cos^2 *(2t) をシンプソン則を用いて求めるプログラムを作成せよ。積分の刻みは0.01毎  という課題がでました。 私は授業で作ったプログラムを元に、以下のプログラムを作ったのですが、答えが大きすぎて(5より大きいと間違いと言っていました)受け取ってもらえません。どこがいけないのでしょうか? あと、nには どのような数字をいれればよいのでしょうか?nは使わないのでしょうか。 お願いします。 #include "stdio.h" #include "math.h" void main() { int n; double i, a, b, h, S, S1, S2, S3; double f (double); a = 0.; b = 5.; printf ("N="); scanf ("%d", &n); h = (b - a) / (double)n; S1 = 0.; S2 = 0.; S3 = f (a) + f (b); /* 両端の値*/ /* 奇数番目の値*/ for (i = 0.01; i < 5; i = i + 0.02) { S1 = S1 + 4. * (f (a + (double)i * h)); } /* 偶数番目の値*/ for (i = 0.0; i < 5; i = i + 0.02) { S2 = S2 + 2. * (f (a + (double)i * h)); } S = (h / 3.) * (S1 + S2 + S3); printf ("%d %lf\n", n, S); } double f (double t) { double y; y = (exp(-3. * t) / 2.) + ((exp(-3.* t) * cos(4. * t)) / 2.); return y; }

みんなの回答

回答No.10

A No.8 です。 アルゴリズムはそれで合っていると思いますよ。 (細かいところは見ていないですが…。) ただ i はもともと double で宣言しているので、(double)i としなくて良いと思います。そのまま a + i で良いです。

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.9

こうだと思います。 #include <stdio.h> #include <math.h> double f(double x) {   return exp(-3 * x) * cos(2 * x) * cos(2 * x); } int main(void) {   double a, b, h, s;   int n, i;      a = 0, b = 5;   h = 0.01;   n = (b - a) / h + 0.5;    // +0.5 は丸め誤差への対応   for (s = 0, i = 1; i < n; i++)     s += ((i % 2 == 0) ? 2 : 4) * f(a + i * h);   s += f(a) + f(b);   s *= h / 3;   printf("面積=%f\n", s);   return 0; } (注)インデントのため、全角空白を使っています。

回答No.8

だんだんまどろっこしくなってきたので… もう言ってしまいますね。。(^^;) i は 0.02 ずつ増えています。 a + (double)i*h は、例えば偶数のほうでは、 a, a + 0.02*h, a + 0.04*h, ..... と増えていきますね。 しかし、ほんとうは、a, a + 0.02, a + 0.04, ... でよいのですから、*h が余分ですよね。 a + i だけで良いです。 奇数のほうでも同様です。 もし a + (double)i * h の形にしたければ、 h = 0.01 刻みで増えていくようにするには、i は 2 刻みで増やさないといけませんね。(i=1,3,5,... と i=0,2,4,... )

gether
質問者

お礼

なかなか理解出来ずにすみません。 このプログラムでよいのでしょうか? 本当にありがとうございました! #include "stdio.h" #include "math.h" void main() { int n; double i, a, b, h, S, S1, S2, S3; double f (double); a = 0.; b = 5.; printf ("N="); scanf ("%d", &n); h = (b - a) / (double)n; S1 = 0.; S2 = 0.; S3 = f (a) + f (b); /* 両端の値*/ /* 奇数番目の値*/ for (i = 0.01; i < 5; i = i + 0.02) { S1 = S1 + 4. * (f (a + (double)i)); } /* 偶数番目の値*/ for (i = 0.0; i < 5; i = i + 0.02) { S2 = S2 + 2. * (f (a + (double)i)); } S = (h / 3.) * (S1 + S2 + S3); printf ("%d %lf\n", n, S); } double f (double t) { double y; y = (exp(-3. * t) / 2.) + ((exp(-3.* t) * cos(4. * t)) / 2.); return y; }

回答No.7

そうですね、i は 0.02 ずつ増えるわけですね。 そのとき、 f() の引数 a + (double)i * h は、a = 0 (の近く)から、どんなふうに増えていくと思いますか? 具体的に数字を順に書いてみたらどうでしょうね? b = 5 (の近く)まで変化していかないといけないわけですが…。

gether
質問者

お礼

a + (double)i * h の aも0.02ずつ値が大きくなるということでしょうか?つまり、 i + (double)i * h でしょうか?

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.6

> 半角の公式や余弦定理などを使い 分解してみました! シンプソンの公式にはそういう変形が必要だとは書いていないです。

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.5

> ∫0~5 e^(-3t) * cos^2 *(2t) 積分したい関数と > y = (exp(-3. * t) / 2.) + ((exp(-3.* t) * cos(4. * t)) / 2.); 実際のコードに書かれたこの式との関係がわかりません。

gether
質問者

お礼

半角の公式や余弦定理などを使い 分解してみました!

回答No.4

できるだけ自分で考えてほしいので、まどろっこしい書き方になってしまいますが…。 > double fの中での t にうまく代入されていないということですか? そういうことではなく… for (i = 0.01; i < 5; i = i + 0.02) では、i はどのように増えていっていますか? そして、 f(a + (double)i * h) と書かれていますが、 この変数は意図したように値が増えていっていますか? よ~く、考えてみてください。 h = ? もしこの式なら、i はどう増えていくべきですか? 修正の仕方は二通りあります。

gether
質問者

お礼

for (i = 0.01; i < 5; i = i + 0.02)は奇数だけを考えるようにしたので0.02ずつ増えていくようにしました。その代わり偶数を考えるfor文も作り、こぼれがないようにしたつもりです。 f(a + (double)i * h) の式の意味が分からなくなってしまいました。今回の問題には使えないような気がしてきました・・・。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

あ, h はその意味なんですね. それなら 3 ですね. 了解です. あと, ちょっとそのプログラムを動かしてみたんだけど危険なところがいくつかありますね. 簡単に列挙すると ・stdio.h や math.h は #include <~> でインクルードすべし ・f の宣言は main の中でしない方が安全 ・やたらと無駄なキャストをし過ぎ ・for で double の変数を動かすのは危険 くらい? ついでにいうと, #2 で挙げられたコメントとは別件で, 多分もう 1つ間違ってますね. 「偶数番目の値」のコメントのあとの for 文があやしい感じ.

gether
質問者

お礼

y = (exp(-3. * t) / 2.) + ((exp(-3.* t) * cos(4. * t)) / 2.) のtに値を入れていくのはdouble fのなかで forで回せばいいのですか? for (i = 0.02; i < 5; i = i + 0.02)にすればよいでしょうか? 質問ばかりですみません!

回答No.2

どこが間違っているのか指摘したら、getherさんの勉強にならないと思うので、ヒントをお教えします。 きざみ幅が0.01で、区間の幅が5なら、きざみの数 n はどうなるか考えてみてください。また、h = (b-a)/n と書いた h は何を表しているのかも考えてみてください。0.01とhの両方がプログラムの中に書かれていますが…。 そして、f(x) の x は loop の中で思ったように増えていっているか、よく考えてみてください。

gether
質問者

お礼

n=500ということでしょうか? hは0.01刻みごとの幅だと考えています。 double fの中での t にうまく代入されていないということですか? 回答ありがとうございました!!

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

あれ? シンプソン則って, 3 で割るんだっけ? なんか, 6 だったような気がするんだけど....

gether
質問者

お礼

ネットで調べたところ 3で正しいようです。 迅速な回答ありがとうございます。

関連するQ&A

  • シンプソン法の出力結果について

    シンプソン法の区間分割数nを10~100まで10ずつ増やして計算値と計算誤差を求めるプログラムを書きに作成したのですが、出力結果に-7.341865999405491E-5などとあります。この「E-数字」とはJavaではどういうこと示しているのですか? また、計算誤差の求め方は下記のプログラムでいいのですか? public class Simpson { static double f(double x) { // ここに任意の被積分関数を記述 double y = Math.exp(- x * x / 2) / Math.sqrt(2.0 * Math.PI); return y; } public static void main(String[] args) { double a = - 1.0, b = 1.0; // 積分範囲 int n = 100; // 区間分割数 for(n=10; n <=100; n+=10){ double h = (b - a) / (double)n; // 分割幅 double s, s1 = 0.0, s2 = 0.0; for (int i = 1; i <= n / 2; i++) { s1 += f(a + (2 * i - 1) * h); } for (int i = 1; i <= n / 2 - 1; i++) { s2 += f(a + 2 * i * h); } s = h / 3.0 * (f(a) + 4.0 * s1 + 2.0 * s2 + f(b)); double suti = (s-0.68269)/0.68269*100;  //計算誤差=(計算値ー真値)/真                                         値×100 System.out.println("区間分割数 =" + n); System.out.println("シンプソン法による計算値 =" + s); System.out.println("シンプソン法による計算誤差 ="+suti+"\n"); } } }

  • 関数の積分を求めるプログラムで質問です。

    シンプソンの公式を用いて積分を求めるプログラムで、 「 y=1/(1+x*x) のように±∞で0に収束するような関数は以下のような無限積分を求めることができる。 ∫(-∞→∞){1/(1+x*x)}dx …(a) ただし、無限区間を分割することはできないので、コンピュータを用いた計算では ∫(-a→a){1/(1+x*x)}dx のaに大きな値を入れることで代用する。この積分を求めるプログラムをシンプソンの式を用いて作成し、以下の3ケースについて値を求めて真値と比較せよ。真値は式(a)を解析的に積分することで求めよ。 ・a=100、N=1000 ・a=100、N=500 ・a=200、N=1000 (Nは以下のプログラムと対応しているものです) 」 というもので参考としてS=∫(1→2){1/x}dxをシンプソンの公式を使い求めるものは以下のものなのですが #include <stdio.h> double f(double x) { return 1/x; } int main() { int i,N; double a,b,h,S; double x[1000],y[1000]; a=1.0; b=2.0; N=10; h=(b-a)/N; for(i=0;i<=N;i++) x[i]=a+i*h; y[0]=f(x[0]); y[N]=f(x[N]); S=h*(y[0]+y[N])/3.0; for(i=1;i<=N-1;i=i+2) { y[i]=f(x[i]); S=S+h*y[i]*4.0/3.0; } for(i=2;i<=N-2;i=i+2) { y[i]=f(x[i]); S=S+h*y[i]*2.0/3.0; } printf("N=%d,S=%15.10lf\n",N,S); } これを生かしてプリグラムをつくりたいのですが、分からなくて困っています。助けてください。

  • 台形公式・シンプソン公式についての質問

    以前質問させていただき実際にプログラミングを作ったのですが、なぜか間違った答えが出てしまいます。 区分求積法・台形公式・シンプソンの公式を用いて、1/1+x*xを求めたいのですが、 1)台形公式の答えが区分求積法の答えより精度がが悪くなってしまう。 2)シンプソン公式が答えに収束しない。 となってしまいます。 以下がそのプログラム↓ #include <stdio.h> #define FROM 0.0 #define TO 1.0 double func(double x) { double out; out = 1.0 / ( 1.0 + x * x ); return (out); } double kubun(double start, double end, int num) { int i; double h, s; h = ( end - start ) / num; s = 0.0; for(i=0; i<num; i++) s += func( start + i * h + h / 2.0 ); return ( s * h ); } double daikei(double start,double end,int num) { int i; double h,s; h = ( end - start ) / num; s = 0.0; for(i=1; i<num-1; i++) s += func( start + i * h ); return ((func(start) / 2.0 + s + func(end) / 2.0) * h ); } double simpson(double start,double end,int num) { int i; double h,s; h = ( end - start ) / num; s = 0.0; for(i=1;i<num;i+=2) s += 4.0 * func(start + h * i); for(i=2;i<num;i+=2) s += 2.0 * func(start + h * i); return ( (func(start) + s + func(end))/ 3 ); } int main() { double func(double); double kubun(double, double, int); double daikei(double, double, int); double simpson(double, double, int); printf("\n"); printf("### Square Integration\n"); printf(" ++ Partition = 10\t Answer = %10.6f\n", kubun(FROM, TO, 10)); printf(" ++ Partition = 50\t Answer = %10.6f\n", kubun(FROM, TO, 50)); printf("\n"); printf("### daikei Integration\n"); printf(" ++ Partition = 10\t Answer = %10.6f\n", daikei(FROM, TO, 10)); printf(" ++ Partition = 50\t Answer = %10.6f\n", daikei(FROM, TO, 50)); printf("\n"); printf("### simpson Integration\n"); printf(" ++ Partition = 10\t Answer = %10.6f\n", simpson(FROM, TO, 10)); printf(" ++ Partition = 50\t Answer = %10.6f\n", simpson(FROM, TO, 50)); return (0); } 画面に表示する際に、それぞれ分割数を10と50にした際の値を表示するように作りました。 細かい点までご指摘いただけると幸いです。 よろしくお願いします。

  • ルンゲクッタのプロクラム実行できません

    プログラムの実行ができません。 どこを直したらよいのか教えて下さい。 よろしくお願いします。 #include <stdio.h> #include <stdlib.h> #include <math.h> double *dvector(long i,long j); void free_dvector(double *a,long i); double func(double x,double y); double *rk4(double y0,double a,double b, int n,double(*f)()); int main(void) { double *y,h,a=0.0, b=1.0, y0=1.0; int i,n; printf("分割数を入力して下さい------->"); scanf("%d",&n); y=dvector(0,n); y=rk4(y0,a,b,n,func); h=(b-a)/n; for(i=0;i<=n;i++) { printf("x=%f \t y=%f \n",a+i*h,y[i]); } return 0; } double *rk4(double y0,double a, double b,int n,double (*f)()) { double k1,k2,k3,k4,h,*y,x; int i; y=dvector(0,n); h=(b-a)/n; y[0]=y0; x=a; for(i=0;i<n;i++) { k1=f(x,y[i]); k2=f(x+h/2.0,y[i]+h*k1/2.0); k3=f(x+h/2.0,y[i]+h*k2/2.0); k4=f(x+h,y[i]+h*k3); y[i+1]=y[i]+h/6.0*(k1+2.0*k2+2.0*k3+k4); x +=h; } return y; free_dvector(y,0); }

  • 値の渡し方?(初心者)

    以前質問したプログラムについて、新たに質問です。 メインプログラムと、関数プログラムを組みました。 関数の中では、print文を使うと計算は正しく行われていて、結果が正しいことが分かりました。 でうが、メイン文の出力では、どこにも出てこない変な値が出てきてしまいます。 値の渡し方がおかしいのでしょうか? 誰か、アドバイスをお願いします。 ***以下プログラムです。*** #include <stdio.h> #include <math.h> double gamma(double x) { double c[9],y,a,r,b,s,z; int i; a=1.; r=1.; c[1]=5.771916e-01; c[2]=9.882058e-01; c[3]=8.970569e-01; c[4]=9.182068e-01; c[5]=7.567040e-01; c[6]=4.821993e-01; c[7]=1.935278e-01; c[8]=3.586834e-02; printf("0 %f\n",x); while(1){ if(x>2.){ x=x-1.; a=a*x; printf("1 %f %f\n",x,a); } else if(x<1.){ a=a/x; x=x+1.; printf("2 %f %f\n",x,a); } else{ break; } } x=x-1.; for(i=1;i<9;i++){ b=(double)(i); s=(c[i]*((double)(pow(-1.,b)))*((double)(pow(x,b)))); printf("3 %d %f\n",i,c[i]); r=r+s; } y=a*r; printf("4 %lf\n",y); return y; } main() { double x,y; printf("数字を入力してください。"); scanf("%lf",&x); printf("メインプログラム x= %lf \n",x); y=gamma(x); printf("x= %f y= %f\n",x,y); }

  • γ関数のプログラム(初心者です)

    以下のようにγ関数のプログラムを組みました。 とりあえず整数値を入力すれば、正しい値は返しているということがprintfの4で確認できました。 もとはfortranで組んだプログラムをCに置き換えました。 ですが、実際走らせてみると、4で値は確認できますがsegmentation faultが出てしまいます。 ですからサブルーチンファイル(ユーザー関数?)として利用できません。 何がいけないのでしょうか? 正しくyが帰ってくるようにどうなおしたらよいのか教えてください。 #include <stdio.h> #include <math.h> double gamma(double x) { double c[8],y,a,r,b,s; int i; a=1.; r=1.; c[1]=5.771916e-01; c[2]=9.882058e-01; c[3]=8.970569e-01; c[4]=9.182068e-01; c[5]=7.567040e-01; c[6]=4.821993e-01; c[7]=1.935278e-01; c[8]=3.586834e-02; printf("0 %f\n",x); while(1){ if(x>2.){ x=x-1.; a=a*x; printf("1 %f %f\n",x,a); } else if(x<1.){ a=a/x; x=x+1.; printf("2 %f %f\n",x,a); } else{ break; } } x=x-1.; for(i=1;i<8;i++){ b=(double)(i); s=(c[i]*((double)(pow(-1,b))) *((double)(pow(x,b)))); printf("3 %d %f\n",i,c[i]); r=r+s; } y=a*(r+(0.03586834*((double)(pow(-1,8)))*((double)(pow(x,8))))); printf("4 %f\n",y); return y; } main() { double x,y; printf("数字を入力してください。"); scanf("%lf",&x); printf("メインプログラム %lf\n",x); y=gamma(x); printf("%f\n",y); }

  • C言語のプログラム

    C言語で2つの微分方程式をEuler法、Heun法、Runge-Kutta法により求めるプログラムを作りたい。ただし、初期条件はx=0,y=1とする。また、間隔Δxを変えたときの解の変化を調べたい。 Euler法のプログラムはどうにか分かったのですが、Heun法、Runge-Kutta法のプログラムがわかりません。 Euler法のプログラム #include_<stdio.h> #include_<math.h> int_main(){ __double__a=0; __double__b; __int_____m=10; __int_____n; __double__h; __double__x,y; __double__dydx; __int_____k; __double__e; __double__f; __printf("オイラー法計算例:y=e^x,_y=1/e^4x\n\n"); __//_y_=_e^x __b_=_1; __for(n=100;n<=10000;n*=100){ ____h_=_(b-a)/n; ____printf("y'_=_y:_h(=dx)_=_%.1e_(y=e^x)\n",h); ____x_=_a;_y_=_1; ____for(k=0;k<=n;k++)_{ ______x_=_k*h; ______if(k%(n/m)==0)_{ ________f_=_exp(x); ________e_=_fabs(y-f); ________printf("x=%.2f,_y=%f,_e^x=%f_er=%.0e\n", ________x,y,f,e); ______} ______dydx_=_y; ______y_=_y_+_dydx*h; ____} __} __printf("\n"); __//_y_=_1/e^4x __b_=_4; __for(n=100;n<=10000;n*=100){ ____h_=_(b-a)/n; ____printf("y'_=_-4y:_h(=dx)_=_%.1e_(y=1/e^4x)\n",h); ____x_=_a;_y_=_1; ____for(k=0;k<=n;k++)_{ ______x_=_k*h; ______if(k%(n/m)==0)_{ ________f_=_exp(-4*x); ________e_=_fabs(y-f); ________printf("x=%.2f,_y=%f,_1/e^4x=%f_er=%.0e\n", ________x,y,f,e); ______} ______dydx_=_-4*y; ______y_=_y_+_dydx*h; ____} __} __return_0; } 分かる方がいましたら、回答よろしくお願いします。

  • 数値解析法

    このHeun法のプログラムをRunge-Kutta法にするにはどうしたらいいですか? #include <stdio.h> #include <math.h> double f1(double y) { return y; } double f2(double y) { return -4*y; } int main(){ double a=0; double b; int m=10; int n; double h; double x,y; int k; double e; double f; double k1,k2; printf("Heun法計算例:y=e^x, y=1/e^4x\n\n"); // y = e^x b = 1; for(n=100;n<=10000;n*=100){ h = (b-a)/n; printf("y' = y: h(=dx) = %.1e (y=e^x)\n",h); x = a; y = 1; for(k=0;k<=n;k++) { x = k*h; if(k%(n/m)==0) { f = exp(x); e = fabs(y-f); printf("x=%.2f, y=%f, e^x=%f er=%.0e\n",x,y,f,e); } // Heun's method k1 = h*f1(y); k2 = h*f1(y+k1); y += (k1+k2)/2; } }

  • プログラミングで・・・

    以下のプログラムにおいて,N回 s=--- s=---  ・  ・  ・ と表示させるにはどうしたらよいでしょか. ----------------------------------------- /*台形公式*/ #include<stdio.h> #include<math.h> double f(double x); int main(void){ /*Define variablest*/ int i,N; double a,b; double dx,xi,s,err; /*Function*/ printf("f=sin(x)+1/2cos10x\n"); /*Integral Field*/ a=0; b=M_PI; printf("a=0\n"); printf("b=pai\n"); /*Inputs data*/ printf("N="); scanf("%d",&N); /*width of integral's range*/ dx=(b-a)/(double)N; s=f(a)*0.5; /*for Loop*/ s=0; for(i=1;i<=N; i++){ xi=a+dx*(double)i; s=s+f(xi); } s=s+f(b)*0.5; s=s*dx; printf("s=%6.3e err=%6.3e\n",s,err); return 0; } double f(double x){ return sin(x)+1/2*cos(10*x); }

  • c プログラム 

    以下のプログラムは,第n項までのe^xのマクローリン展開をさせるものです. これを修正して,理論値と近似値の誤差がある値(自分で入力)になったときに,計算を終了させるにはどうしたらよいでしょうか.御教授いただければ幸甚 です. ---------------------------------------- #include <stdio.h> #include <math.h> int main(void) { int n; double x=1.0,y=1.0,e=1.0,err; int i; double f=1.0,p=1.0; printf("x="); scanf("%lf",&x); printf("n="); scanf("%d",&n); printf("Mclaurin展開によるn項までのexp(x)の\n n 理論値 近似値 誤差\n"); for(i=1;i<=n;i++){ f*=(double)i; p*=x; y+=p/f;近似値 e=exp(x);理論値 err=e-y;誤差 printf("%2d %12.8e %12.8e %12.8e\n",i,e,y,err); } return 0; }

専門家に質問してみよう