バーラル @ ウィキ

[Cで数値積分(ニュートンコーツ法・チェビシェフ公式・ガウス公式)]の変更点

「Cで数値積分(ニュートンコーツ法・チェビシェフ公式・ガウス公式)」の編集履歴(バックアップ)一覧はこちら

Cで数値積分(ニュートンコーツ法・チェビシェフ公式・ガウス公式)」(2011/01/18 (火) 16:04:30) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

*数値積分について **ニートンコーツ法、チェビシェフ公式、ガウス公式を用いた計算 <<<program>>> #include<stdio.h> #include<math.h> double fun( double x) { //return x*exp(x); return ((x+2)*x+3)*x+4; } double scale( double x, double x0, double x1 ) { return (x0 * (1.0 - x) + x1 * (1.0 + x)) / 2.0; } double newton_cote(int n,double xfrom_local,double xto_local,int xdivision){ int xidx; double x1,x2,x3,x4,sum; sum=0; if(n==1){ for (xidx=1; xidx<xdivision; xidx++) { x1 = (xfrom_local * (xdivision - xidx) + xto_local * xidx) / xdivision; sum += fun( x1 ); } sum *= 2; sum += fun( xfrom_local ) + fun( xto_local ); sum = (xto_local - xfrom_local) * sum / ( 2.0 * xdivision ); }else if(n==2){ if(xdivision%2==0){ for (xidx=0; xidx<=((xdivision/2)-1); xidx++) { x1 = (xfrom_local * (xdivision - 2*xidx) + xto_local * 2*xidx) / xdivision; x2 = (xfrom_local * (xdivision - (2*xidx+1)) + xto_local * (2*xidx+1)) / xdivision; x3 = (xfrom_local * (xdivision - (2*xidx+2)) + xto_local * (2*xidx+2)) / xdivision; sum += (fun(x1)+4*fun(x2)+fun(x3)); } sum = (xto_local - xfrom_local) * sum / ( 3.0 * xdivision); }else{ sum = -1;//error } }else if(n==3){ if(xdivision%3==0){ for (xidx=0; xidx<=((xdivision/3)-1); xidx++) { x1 = (xfrom_local * (xdivision - 3*xidx) + xto_local * 3*xidx) / xdivision; x2 = (xfrom_local * (xdivision - (3*xidx+1)) + xto_local * (3*xidx+1)) / xdivision; x3 = (xfrom_local * (xdivision - (3*xidx+2)) + xto_local * (3*xidx+2)) / xdivision; x4 = (xfrom_local * (xdivision - (3*xidx+3)) + xto_local * (3*xidx+3)) / xdivision; sum += (fun(x1)+3*fun(x2)+3*fun(x3)+fun(x4)); } sum = 3.0 * (xto_local - xfrom_local) * sum / ( 8.0 * xdivision); }else{ sum = -1;//error } } return sum; } double chebyshev(int n,double xfrom_local,double xto_local,int xdivision){ double x0, x1, y; int xidx; xdivision=(int)(xdivision/3);//hikakunotame y = 0; x0 = xfrom_local; for( xidx=1; xidx<=xdivision; xidx++ ) { x1 = (xfrom_local * (xdivision - xidx) + xto_local * xidx) / xdivision; y += ( fun( scale( -1.0/sqrt(2.0), x0, x1 ) ) + fun( scale( 0.0,x0, x1 ) ) + fun( scale( +1.0/sqrt(2.0), x0, x1 ) ) ) * (x1 - x0) / 3.0; x0 = x1; } return y; } double gauss(int n,double xfrom_local,double xto_local,int xdivision){ double x0, x1, y; int xidx; xdivision=(int)(xdivision/3);//hikakunotame y = 0; x0 = xfrom_local; for( xidx=1; xidx<=xdivision; xidx++ ) { x1 = (xfrom_local * (xdivision - xidx) + xto_local * xidx) / xdivision; y += ( (5.0/9.0) * fun( scale( -sqrt(3.0/5.0), x0, x1 ) ) + (8.0/9.0) * fun( scale(0.0, x0, x1 ) ) + (5.0/9.0) * fun( scale( +sqrt(3.0/5.0), x0, x1 ) ) ) * (x1 - x0) / 2.0; x0 = x1; } return y; } int main(void){ double ans; double xfrom, xto,true_value; int xdivision; //init //true_value=2/exp(1); true_value=28.0/3.0; xfrom=-1; xto=1; printf("division number(xdivision) > "); scanf( "%d",&xdivision ); do{ printf( "true value:\t%20.15lf\n", true_value ); ans=newton_cote(1,xfrom,xto,xdivision); printf( "newton_cote(1):\t%20.15lf\n", ans ); ans=newton_cote(2,xfrom,xto,xdivision); printf( "newton_cote(2):\t%20.15lf\n", ans ); ans=newton_cote(3,xfrom,xto,xdivision); printf( "newton_cote(3):\t%20.15lf\n", ans ); ans=chebyshev(3,xfrom,xto,xdivision); printf( "chebyshev(3):\t%20.15lf\n", ans ); ans=gauss(3,xfrom,xto,xdivision); printf( "gauss(3):\t%20.15lf\n", ans ); printf("division number(xdivision) (if(xdivision<=0){END}) > "); scanf( "%d",&xdivision ); }while(xdivision>0); return 0; } ---- ***<<<results-1(x*exp(x))>>>与えられた課題のsimpsonの公式のみを出力したもの division number(xdivision) > 2 newton_cote(2): 0.783467462429201 division number(xdivision) (if(xdivision<=0){END}) > 4 newton_cote(2): 0.739130601543765 division number(xdivision) (if(xdivision<=0){END}) > 6 newton_cote(2): 0.736440917298669 division number(xdivision) (if(xdivision<=0){END}) > 8 newton_cote(2): 0.735976501958868 division number(xdivision) (if(xdivision<=0){END}) > 10 newton_cote(2): 0.735848367669737 division number(xdivision) (if(xdivision<=0){END}) > 20 newton_cote(2): 0.735764504414181 division number(xdivision) (if(xdivision<=0){END}) > 40 newton_cote(2): 0.735759234181559 division number(xdivision) (if(xdivision<=0){END}) > 80 newton_cote(2): 0.735758904339986 division number(xdivision) (if(xdivision<=0){END}) > 200 newton_cote(2): 0.735758882906062 division number(xdivision) (if(xdivision<=0){END}) > 500 newton_cote(2): 0.735758882357302 division number(xdivision) (if(xdivision<=0){END}) > 1000 newton_cote(2): 0.735758882343786 division number(xdivision) (if(xdivision<=0){END}) > 2000 newton_cote(2): 0.735758882342941 division number(xdivision) (if(xdivision<=0){END}) > 5000 newton_cote(2): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 10000 newton_cote(2): 0.735758882342883 division number(xdivision) (if(xdivision<=0){END}) > 30000 newton_cote(2): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 80000 newton_cote(2): 0.735758882342884 division number(xdivision) (if(xdivision<=0){END}) > 100000 newton_cote(2): 0.735758882342886 division number(xdivision) (if(xdivision<=0){END}) >0 ---- ***<<<results-2(x*exp(x))>>>真の値、台形公式、simpsonの公式、simpsonの3/8公式、チェビシェフ、ガウスの順に計算したもの division number(xdivision) > 6 true value: 0.735758882342885 newton_cote(1): 0.785924282165319 newton_cote(2): 0.736440917298669 newton_cote(3): 0.737264668230509 chebyshev(3): 0.734912297016692 gauss(3): 0.735751841168723 division number(xdivision) (if(xdivision<=0){END}) > 12 true value: 0.735758882342885 newton_cote(1): 0.748332666995611 newton_cote(2): 0.735802128605708 newton_cote(3): 0.735855719173966 chebyshev(3): 0.735704418254167 gauss(3): 0.735758768617193 division number(xdivision) (if(xdivision<=0){END}) > 30 true value: 0.735758882342885 newton_cote(1): 0.737772146364007 newton_cote(2): 0.735759993950277 newton_cote(3): 0.735761381524993 chebyshev(3): 0.735757476580191 gauss(3): 0.735758881872675 division number(xdivision) (if(xdivision<=0){END}) > 60 true value: 0.735758882342885 newton_cote(1): 0.736262250485027 newton_cote(2): 0.735758951858701 newton_cote(3): 0.735759038723198 chebyshev(3): 0.735758794379384 gauss(3): 0.735758882335528 division number(xdivision) (if(xdivision<=0){END}) > 300 true value: 0.735758882342885 newton_cote(1): 0.735779017736025 newton_cote(2): 0.735758882454131 newton_cote(3): 0.735758882593186 chebyshev(3): 0.735758882202090 gauss(3): 0.735758882342884 division number(xdivision) (if(xdivision<=0){END}) > 600 true value: 0.735758882342885 newton_cote(1): 0.735763916196385 newton_cote(2): 0.735758882349838 newton_cote(3): 0.735758882358529 chebyshev(3): 0.735758882334085 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 3000 true value: 0.735758882342885 newton_cote(1): 0.735759083697091 newton_cote(2): 0.735758882342896 newton_cote(3): 0.735758882342909 chebyshev(3): 0.735758882342871 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 6000 true value: 0.735758882342885 newton_cote(1): 0.735758932681438 newton_cote(2): 0.735758882342885 newton_cote(3): 0.735758882342886 chebyshev(3): 0.735758882342885 gauss(3): 0.735758882342886 division number(xdivision) (if(xdivision<=0){END}) > 0 ---- ***<<<results-3(((x+2)*x+3)*x+4)>>>自分で設定した被積分関数について 真の値、台形公式、simpsonの公式、simpsonの3/8公式、チェビシェフ、ガウスの順に計算したもの division number(xdivision) > 6 true value: 9.333333333333334 newton_cote(1): 9.407407407407407 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333334 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333332 division number(xdivision) (if(xdivision<=0){END}) > 12 true value: 9.333333333333334 newton_cote(1): 9.351851851851849 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333332 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333332 division number(xdivision) (if(xdivision<=0){END}) > 30 true value: 9.333333333333334 newton_cote(1): 9.336296296296297 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333334 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333334 division number(xdivision) (if(xdivision<=0){END}) > 60 true value: 9.333333333333334 newton_cote(1): 9.334074074074074 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333334 chebyshev(3): 9.333333333333336 gauss(3): 9.333333333333334 division number(xdivision) (if(xdivision<=0){END}) > 300 true value: 9.333333333333334 newton_cote(1): 9.333362962962966 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333330 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333332 division number(xdivision) (if(xdivision<=0){END}) > 600 true value: 9.333333333333334 newton_cote(1): 9.333340740740741 newton_cote(2): 9.333333333333327 newton_cote(3): 9.333333333333336 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333334 division number(xdivision) (if(xdivision<=0){END}) > 3000 true value: 9.333333333333334 newton_cote(1): 9.333333629629646 newton_cote(2): 9.333333333333323 newton_cote(3): 9.333333333333343 chebyshev(3): 9.333333333333330 gauss(3): 9.333333333333330 division number(xdivision) (if(xdivision<=0){END}) > 6000 true value: 9.333333333333334 newton_cote(1): 9.333333407407418 newton_cote(2): 9.333333333333341 newton_cote(3): 9.333333333333332 chebyshev(3): 9.333333333333327 gauss(3): 9.333333333333327 division number(xdivision) (if(xdivision<=0){END}) > 0 ---- **<<<考察1(精度について考える)>>> シンプソンの公式で得られた結果をまとめると以下のようになる。 newton_cote(2): 0.783467462429201[2] newton_cote(2): 0.739130601543765[4] newton_cote(2): 0.736440917298669[6] newton_cote(2): 0.735976501958868[8] newton_cote(2): 0.735848367669737[10] newton_cote(2): 0.735764504414181[20] newton_cote(2): 0.735759234181559[40] newton_cote(2): 0.735758904339986[80] newton_cote(2): 0.735758882906062[200] newton_cote(2): 0.735758882357302[500] newton_cote(2): 0.735758882343786[1000] newton_cote(2): 0.735758882342941[2000] newton_cote(2): 0.735758882342885[5000] newton_cote(2): 0.735758882342883[10000] newton_cote(2): 0.735758882342885[30000] newton_cote(2): 0.735758882342884[80000] newton_cote(2): 0.735758882342886[100000] true value: 0.735758882342885 正しい桁数まで表示してみると・・・ newton_cote(2): 0.7[2] newton_cote(2): 0.73[4] newton_cote(2): 0.73[6] newton_cote(2): 0.735[8] newton_cote(2): 0.735[10] newton_cote(2): 0.7357[20] newton_cote(2): 0.73575[40] newton_cote(2): 0.735758[80] newton_cote(2): 0.735758882[200] newton_cote(2): 0.7357588823[500] newton_cote(2): 0.73575888234[1000] newton_cote(2): 0.735758882342[2000] newton_cote(2): 0.735758882342885[5000] newton_cote(2): 0.73575888234288[10000] newton_cote(2): 0.735758882342885[30000] newton_cote(2): 0.73575888234288[80000] newton_cote(2): 0.73575888234288[100000] true value: 0.735758882342885 これより、全桁正しいのは5000分割したときなのだが、それ以降増やしていくと最後の桁がずれていることに気づく。求めたい精度の桁数に対して、適切な分割数があると考えられる。 また、分割数を10倍したもののみ見てみると・・・ newton_cote(2): 0.7[2] 有効数字1桁 newton_cote(2): 0.7357[20] 有効数字4桁 newton_cote(2): 0.735758882[200] 有効数字9桁(8桁) newton_cote(2): 0.735758882342[2000] 有効数字12桁 分割数200のとき最後の有効が偶然合ったとして有効数字8桁とすると・・・ 分割数を10倍するごとに有効数字が4桁多くなっていることがわかる。(だいたい) 文献によると・・シンプソンの公式(閉じた式)の誤差項は-h^5*f(4)/90とのことなので、誤差項のオーダーがh^5によると簡易化して考えてみる。 h=(xto-xfrom)/xdivisionよりhは分割数に反比例するので、分割数が10倍になると、オーダーが5桁上がるはずだが、実際のところ4桁しか上がっていない。 これの原因として、上の誤差項は閉じた式の誤差項なので、実際のプログラムではその誤差項をfor文のなかで、((xdivision/2)-1)回繰り返していることから、誤差が((xdivision/2)-1)回たまるとすると(h^5*xdivisionと簡易化して)、オーダーはだいたいh^4となっているのではないか。 ---- **<<<考察2(関数が違った場合について考える)>>> 被積分関数が違った場合・・・(今回は以下の場合) return x*exp(x); return ((x+2)*x+3)*x+4; このとき、分割数を6にしたときから、台形公式以外で求めた積分値はほぼ真の値を示している。これは被積分関数が、xの多項式であるからかもしれない(実験不足で自信がありません)アルゴリズム的にラグランジュ補間式を用いているからであるかもしれない。 ---- **<<<考察3おまけ(区間毎に Chebyshev 公式や Gauss 公式を用いた結果とも比較 )>>> 結果2を必要な公式で計算したもののみ取り出し、真の値と同じ桁のみ残したものが以下である。プログラム中のscale関数でチェビシェフとガウスは分割しているとみなして、同じ分割数にするため、xdivision =xdivision/3としている。これで比較してみると・・・ division number(xdivision) > 6 newton_cote(3): 0.73 chebyshev(3): 0.73 gauss(3): 0.73575 division number(xdivision) (if(xdivision<=0){END}) > 12 newton_cote(3): 0.735 chebyshev(3): 0.7357 gauss(3): 0.735758 division number(xdivision) (if(xdivision<=0){END}) > 30 newton_cote(3): 0.7357 chebyshev(3): 0.73575 gauss(3): 0.73575888 division number(xdivision) (if(xdivision<=0){END}) > 60 newton_cote(3): 0.73575 chebyshev(3): 0.735758 gauss(3): 0.7357588823 division number(xdivision) (if(xdivision<=0){END}) > 300 newton_cote(3): 0.735758882 chebyshev(3): 0.735758882 gauss(3): 0.73575888234288 division number(xdivision) (if(xdivision<=0){END}) > 600 newton_cote(3): 0.7357588823 chebyshev(3): 0.7357588823 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 3000 newton_cote(3): 0.735758882342 chebyshev(3): 0.7357588823428 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 6000 newton_cote(3): 0.73575888234288 chebyshev(3): 0.73575888234288 gauss(3): 0.73575888234288 ガウス公式は収束がはやい。 シンプソンの3/8公式とチェビシェフ公式はほぼ同じくらいで若干チェビシェフ公式が早い。 (シンプソンの3/8公式よりこれだけ収束が早いということは何か比較を間違えているかもしれない・・・あるいは、たまたま早く求まる関数だったのかもしれない。) ----
*数値積分について **ニートンコーツ法、チェビシェフ公式、ガウス公式を用いた計算 <<<program>>> #include<stdio.h> #include<math.h> double fun( double x) { //return x*exp(x); return ((x+2)*x+3)*x+4; } double scale( double x, double x0, double x1 ) { return (x0 * (1.0 - x) + x1 * (1.0 + x)) / 2.0; } double newton_cote(int n,double xfrom_local,double xto_local,int xdivision){ int xidx; double x1,x2,x3,x4,sum; sum=0; if(n==1){ for (xidx=1; xidx<xdivision; xidx++) { x1 = (xfrom_local * (xdivision - xidx) + xto_local * xidx) / xdivision; sum += fun( x1 ); } sum *= 2; sum += fun( xfrom_local ) + fun( xto_local ); sum = (xto_local - xfrom_local) * sum / ( 2.0 * xdivision ); }else if(n==2){ if(xdivision%2==0){ for (xidx=0; xidx<=((xdivision/2)-1); xidx++) { x1 = (xfrom_local * (xdivision - 2*xidx) + xto_local * 2*xidx) / xdivision; x2 = (xfrom_local * (xdivision - (2*xidx+1)) + xto_local * (2*xidx+1)) / xdivision; x3 = (xfrom_local * (xdivision - (2*xidx+2)) + xto_local * (2*xidx+2)) / xdivision; sum += (fun(x1)+4*fun(x2)+fun(x3)); } sum = (xto_local - xfrom_local) * sum / ( 3.0 * xdivision); }else{ sum = -1;//error } }else if(n==3){ if(xdivision%3==0){ for (xidx=0; xidx<=((xdivision/3)-1); xidx++) { x1 = (xfrom_local * (xdivision - 3*xidx) + xto_local * 3*xidx) / xdivision; x2 = (xfrom_local * (xdivision - (3*xidx+1)) + xto_local * (3*xidx+1)) / xdivision; x3 = (xfrom_local * (xdivision - (3*xidx+2)) + xto_local * (3*xidx+2)) / xdivision; x4 = (xfrom_local * (xdivision - (3*xidx+3)) + xto_local * (3*xidx+3)) / xdivision; sum += (fun(x1)+3*fun(x2)+3*fun(x3)+fun(x4)); } sum = 3.0 * (xto_local - xfrom_local) * sum / ( 8.0 * xdivision); }else{ sum = -1;//error } } return sum; } double chebyshev(int n,double xfrom_local,double xto_local,int xdivision){ double x0, x1, y; int xidx; xdivision=(int)(xdivision/3);//hikakunotame y = 0; x0 = xfrom_local; for( xidx=1; xidx<=xdivision; xidx++ ) { x1 = (xfrom_local * (xdivision - xidx) + xto_local * xidx) / xdivision; y += ( fun( scale( -1.0/sqrt(2.0), x0, x1 ) ) + fun( scale( 0.0,x0, x1 ) ) + fun( scale( +1.0/sqrt(2.0), x0, x1 ) ) ) * (x1 - x0) / 3.0; x0 = x1; } return y; } double gauss(int n,double xfrom_local,double xto_local,int xdivision){ double x0, x1, y; int xidx; xdivision=(int)(xdivision/3);//hikakunotame y = 0; x0 = xfrom_local; for( xidx=1; xidx<=xdivision; xidx++ ) { x1 = (xfrom_local * (xdivision - xidx) + xto_local * xidx) / xdivision; y += ( (5.0/9.0) * fun( scale( -sqrt(3.0/5.0), x0, x1 ) ) + (8.0/9.0) * fun( scale(0.0, x0, x1 ) ) + (5.0/9.0) * fun( scale( +sqrt(3.0/5.0), x0, x1 ) ) ) * (x1 - x0) / 2.0; x0 = x1; } return y; } int main(void){ double ans; double xfrom, xto,true_value; int xdivision; //init //true_value=2/exp(1); true_value=28.0/3.0; xfrom=-1; xto=1; printf("division number(xdivision) > "); scanf( "%d",&xdivision ); do{ printf( "true value:\t%20.15lf\n", true_value ); ans=newton_cote(1,xfrom,xto,xdivision); printf( "newton_cote(1):\t%20.15lf\n", ans ); ans=newton_cote(2,xfrom,xto,xdivision); printf( "newton_cote(2):\t%20.15lf\n", ans ); ans=newton_cote(3,xfrom,xto,xdivision); printf( "newton_cote(3):\t%20.15lf\n", ans ); ans=chebyshev(3,xfrom,xto,xdivision); printf( "chebyshev(3):\t%20.15lf\n", ans ); ans=gauss(3,xfrom,xto,xdivision); printf( "gauss(3):\t%20.15lf\n", ans ); printf("division number(xdivision) (if(xdivision<=0){END}) > "); scanf( "%d",&xdivision ); }while(xdivision>0); return 0; } ---- ***<<<results-1(x*exp(x))>>>与えられた課題のsimpsonの公式のみを出力したもの division number(xdivision) > 2 newton_cote(2): 0.783467462429201 division number(xdivision) (if(xdivision<=0){END}) > 4 newton_cote(2): 0.739130601543765 division number(xdivision) (if(xdivision<=0){END}) > 6 newton_cote(2): 0.736440917298669 division number(xdivision) (if(xdivision<=0){END}) > 8 newton_cote(2): 0.735976501958868 division number(xdivision) (if(xdivision<=0){END}) > 10 newton_cote(2): 0.735848367669737 division number(xdivision) (if(xdivision<=0){END}) > 20 newton_cote(2): 0.735764504414181 division number(xdivision) (if(xdivision<=0){END}) > 40 newton_cote(2): 0.735759234181559 division number(xdivision) (if(xdivision<=0){END}) > 80 newton_cote(2): 0.735758904339986 division number(xdivision) (if(xdivision<=0){END}) > 200 newton_cote(2): 0.735758882906062 division number(xdivision) (if(xdivision<=0){END}) > 500 newton_cote(2): 0.735758882357302 division number(xdivision) (if(xdivision<=0){END}) > 1000 newton_cote(2): 0.735758882343786 division number(xdivision) (if(xdivision<=0){END}) > 2000 newton_cote(2): 0.735758882342941 division number(xdivision) (if(xdivision<=0){END}) > 5000 newton_cote(2): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 10000 newton_cote(2): 0.735758882342883 division number(xdivision) (if(xdivision<=0){END}) > 30000 newton_cote(2): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 80000 newton_cote(2): 0.735758882342884 division number(xdivision) (if(xdivision<=0){END}) > 100000 newton_cote(2): 0.735758882342886 division number(xdivision) (if(xdivision<=0){END}) >0 ---- ***<<<results-2(x*exp(x))>>>真の値、台形公式、simpsonの公式、simpsonの3/8公式、チェビシェフ、ガウスの順に計算したもの division number(xdivision) > 6 true value: 0.735758882342885 newton_cote(1): 0.785924282165319 newton_cote(2): 0.736440917298669 newton_cote(3): 0.737264668230509 chebyshev(3): 0.734912297016692 gauss(3): 0.735751841168723 division number(xdivision) (if(xdivision<=0){END}) > 12 true value: 0.735758882342885 newton_cote(1): 0.748332666995611 newton_cote(2): 0.735802128605708 newton_cote(3): 0.735855719173966 chebyshev(3): 0.735704418254167 gauss(3): 0.735758768617193 division number(xdivision) (if(xdivision<=0){END}) > 30 true value: 0.735758882342885 newton_cote(1): 0.737772146364007 newton_cote(2): 0.735759993950277 newton_cote(3): 0.735761381524993 chebyshev(3): 0.735757476580191 gauss(3): 0.735758881872675 division number(xdivision) (if(xdivision<=0){END}) > 60 true value: 0.735758882342885 newton_cote(1): 0.736262250485027 newton_cote(2): 0.735758951858701 newton_cote(3): 0.735759038723198 chebyshev(3): 0.735758794379384 gauss(3): 0.735758882335528 division number(xdivision) (if(xdivision<=0){END}) > 300 true value: 0.735758882342885 newton_cote(1): 0.735779017736025 newton_cote(2): 0.735758882454131 newton_cote(3): 0.735758882593186 chebyshev(3): 0.735758882202090 gauss(3): 0.735758882342884 division number(xdivision) (if(xdivision<=0){END}) > 600 true value: 0.735758882342885 newton_cote(1): 0.735763916196385 newton_cote(2): 0.735758882349838 newton_cote(3): 0.735758882358529 chebyshev(3): 0.735758882334085 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 3000 true value: 0.735758882342885 newton_cote(1): 0.735759083697091 newton_cote(2): 0.735758882342896 newton_cote(3): 0.735758882342909 chebyshev(3): 0.735758882342871 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 6000 true value: 0.735758882342885 newton_cote(1): 0.735758932681438 newton_cote(2): 0.735758882342885 newton_cote(3): 0.735758882342886 chebyshev(3): 0.735758882342885 gauss(3): 0.735758882342886 division number(xdivision) (if(xdivision<=0){END}) > 0 ---- ***<<<results-3(((x+2)*x+3)*x+4)>>>自分で設定した被積分関数について 真の値、台形公式、simpsonの公式、simpsonの3/8公式、チェビシェフ、ガウスの順に計算したもの division number(xdivision) > 6 true value: 9.333333333333334 newton_cote(1): 9.407407407407407 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333334 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333332 division number(xdivision) (if(xdivision<=0){END}) > 12 true value: 9.333333333333334 newton_cote(1): 9.351851851851849 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333332 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333332 division number(xdivision) (if(xdivision<=0){END}) > 30 true value: 9.333333333333334 newton_cote(1): 9.336296296296297 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333334 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333334 division number(xdivision) (if(xdivision<=0){END}) > 60 true value: 9.333333333333334 newton_cote(1): 9.334074074074074 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333334 chebyshev(3): 9.333333333333336 gauss(3): 9.333333333333334 division number(xdivision) (if(xdivision<=0){END}) > 300 true value: 9.333333333333334 newton_cote(1): 9.333362962962966 newton_cote(2): 9.333333333333334 newton_cote(3): 9.333333333333330 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333332 division number(xdivision) (if(xdivision<=0){END}) > 600 true value: 9.333333333333334 newton_cote(1): 9.333340740740741 newton_cote(2): 9.333333333333327 newton_cote(3): 9.333333333333336 chebyshev(3): 9.333333333333334 gauss(3): 9.333333333333334 division number(xdivision) (if(xdivision<=0){END}) > 3000 true value: 9.333333333333334 newton_cote(1): 9.333333629629646 newton_cote(2): 9.333333333333323 newton_cote(3): 9.333333333333343 chebyshev(3): 9.333333333333330 gauss(3): 9.333333333333330 division number(xdivision) (if(xdivision<=0){END}) > 6000 true value: 9.333333333333334 newton_cote(1): 9.333333407407418 newton_cote(2): 9.333333333333341 newton_cote(3): 9.333333333333332 chebyshev(3): 9.333333333333327 gauss(3): 9.333333333333327 division number(xdivision) (if(xdivision<=0){END}) > 0 ---- **<<<考察1(精度について考える)>>> シンプソンの公式で得られた結果をまとめると以下のようになる。 newton_cote(2): 0.783467462429201[2] newton_cote(2): 0.739130601543765[4] newton_cote(2): 0.736440917298669[6] newton_cote(2): 0.735976501958868[8] newton_cote(2): 0.735848367669737[10] newton_cote(2): 0.735764504414181[20] newton_cote(2): 0.735759234181559[40] newton_cote(2): 0.735758904339986[80] newton_cote(2): 0.735758882906062[200] newton_cote(2): 0.735758882357302[500] newton_cote(2): 0.735758882343786[1000] newton_cote(2): 0.735758882342941[2000] newton_cote(2): 0.735758882342885[5000] newton_cote(2): 0.735758882342883[10000] newton_cote(2): 0.735758882342885[30000] newton_cote(2): 0.735758882342884[80000] newton_cote(2): 0.735758882342886[100000] true value: 0.735758882342885 正しい桁数まで表示してみると・・・ newton_cote(2): 0.7[2] newton_cote(2): 0.73[4] newton_cote(2): 0.73[6] newton_cote(2): 0.735[8] newton_cote(2): 0.735[10] newton_cote(2): 0.7357[20] newton_cote(2): 0.73575[40] newton_cote(2): 0.735758[80] newton_cote(2): 0.735758882[200] newton_cote(2): 0.7357588823[500] newton_cote(2): 0.73575888234[1000] newton_cote(2): 0.735758882342[2000] newton_cote(2): 0.735758882342885[5000] newton_cote(2): 0.73575888234288[10000] newton_cote(2): 0.735758882342885[30000] newton_cote(2): 0.73575888234288[80000] newton_cote(2): 0.73575888234288[100000] true value: 0.735758882342885 これより、全桁正しいのは5000分割したときなのだが、それ以降増やしていくと最後の桁がずれていることに気づく。求めたい精度の桁数に対して、適切な分割数があると考えられる。 また、分割数を10倍したもののみ見てみると・・・ newton_cote(2): 0.7[2] 有効数字1桁 newton_cote(2): 0.7357[20] 有効数字4桁 newton_cote(2): 0.735758882[200] 有効数字9桁(8桁) newton_cote(2): 0.735758882342[2000] 有効数字12桁 分割数200のとき最後の有効が偶然合ったとして有効数字8桁とすると・・・ 分割数を10倍するごとに有効数字が4桁多くなっていることがわかる。(だいたい) 文献によると・・シンプソンの公式(閉じた式)の誤差項は-h^5*f(4)/90とのことなので、誤差項のオーダーがh^5によると簡易化して考えてみる。 h=(xto-xfrom)/xdivisionよりhは分割数に反比例するので、分割数が10倍になると、オーダーが5桁上がるはずだが、実際のところ4桁しか上がっていない。 これの原因として、上の誤差項は閉じた式の誤差項なので、実際のプログラムではその誤差項をfor文のなかで、((xdivision/2)-1)回繰り返していることから、誤差が((xdivision/2)-1)回たまるとすると(h^5*xdivisionと簡易化して)、オーダーはだいたいh^4となっているのではないか。 ---- **<<<考察2(関数が違った場合について考える)>>> 被積分関数が違った場合・・・(今回は以下の場合) return x*exp(x); return ((x+2)*x+3)*x+4; このとき、分割数を6にしたときから、台形公式以外で求めた積分値はほぼ真の値を示している。これは被積分関数が、xの多項式であるからかもしれない(実験不足で自信がありません)アルゴリズム的にラグランジュ補間式を用いているからであるかもしれない。 ---- **<<<考察3おまけ(区間毎に Chebyshev 公式や Gauss 公式を用いた結果とも比較 )>>> 結果2を必要な公式で計算したもののみ取り出し、真の値と同じ桁のみ残したものが以下である。プログラム中のscale関数でチェビシェフとガウスは分割しているとみなして、同じ分割数にするため、xdivision =xdivision/3としている。これで比較してみると・・・ division number(xdivision) > 6 newton_cote(3): 0.73 chebyshev(3): 0.73 gauss(3): 0.73575 division number(xdivision) (if(xdivision<=0){END}) > 12 newton_cote(3): 0.735 chebyshev(3): 0.7357 gauss(3): 0.735758 division number(xdivision) (if(xdivision<=0){END}) > 30 newton_cote(3): 0.7357 chebyshev(3): 0.73575 gauss(3): 0.73575888 division number(xdivision) (if(xdivision<=0){END}) > 60 newton_cote(3): 0.73575 chebyshev(3): 0.735758 gauss(3): 0.7357588823 division number(xdivision) (if(xdivision<=0){END}) > 300 newton_cote(3): 0.735758882 chebyshev(3): 0.735758882 gauss(3): 0.73575888234288 division number(xdivision) (if(xdivision<=0){END}) > 600 newton_cote(3): 0.7357588823 chebyshev(3): 0.7357588823 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 3000 newton_cote(3): 0.735758882342 chebyshev(3): 0.7357588823428 gauss(3): 0.735758882342885 division number(xdivision) (if(xdivision<=0){END}) > 6000 newton_cote(3): 0.73575888234288 chebyshev(3): 0.73575888234288 gauss(3): 0.73575888234288 ガウス公式は収束がはやい。 シンプソンの3/8公式とチェビシェフ公式はほぼ同じくらいで若干チェビシェフ公式が早い。 (シンプソンの3/8公式よりこれだけ収束が早いということは何か比較を間違えているかもしれない・・・あるいは、たまたま早く求まる関数だったのかもしれない。) ----

表示オプション

横に並べて表示:
変化行の前後のみ表示: