• 締切済み

オイラー法

区間[0,10]においてh=0.01としオイラー法を用いてとけ。また誤差も出せ。 y'=3x^2-x^3-x^6+(2x^3+1)y-y^2 y(0)=0.5 なんですけどa=3くらいから値がおかしくなりa=10の時には誤差ですぎます。誤差がでないようにするにはどこを直せばいいのか教えてください。 おねがいします。 #include<stdio.h> #include<math.h> double h=0.01; double x0=0.5; main(void) { int a; double euler(int a); double gosa; for(a=1;a<=10;a++) gosa=shin(a)-euler(a); printf("%d %f %f\n",a,euler(a),gosa); } double shin(double a) { double y; y=a*a*a+1.0/(1.0+exp(-a)); return y; } double f(double t,double x){ double y; y = 3.0*t*t-t*t*t-t*t*t*t*t*t+(2.0*t*t*t+1.0)*x-x*x; return y; } /* Euler Function */ double euler(int a){// x0:Initial Value double T,nx,x; // Initial Value x = x0; // Euler Method for(T = 0.0;T < a;T += h){ nx = x + h*f(T,x); x = nx; }

みんなの回答

  • A-Tanaka
  • ベストアンサー率44% (88/196)
回答No.1

こんにちは。 オイラー法というより、これは誤差関数式の問題ですね。 for(T = 0.0;T < a;T += h){ nx = x + h*f(T,x); x = nx; } の式において、ステップを与えるのが、初期に与えられたパラメータに依存しますよね? つまり、この初期に与えられたパラメータを、更に小さくしてみてください。 つまり、h=0.001とかh=0.001にしてみればよいかと思います。 付記)デジタル方式の計算機を用いた数値計算においては、誤差計算を行う場合には求めたい値よりも小さなステップで計算を行うことが重要です。たまたま手元に、Numerical Recipes in Cの原書があるのですが、ここでも誤差や計算式の安定性についての記述があります。このような点を参考にして計算を行ってみてください。 なお、大きな数値を取り扱う場合には、誤差が許容される場合もあります。例をあげますと、宇宙の年齢は137億年±2億年という世界になりますが、この計算において1年とかいうステップは・・・誤差の範囲になります。

vcxsdfrew
質問者

お礼

ありがとうございます

関連するQ&A

  • 数値解析法

    この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; } }

  • オイラー法のCプログラムについて

    x1[i+1]=x1[i]+x2[i]*t x2[i+1]=x2[i]+(-2ab*x2[i]-a^2*x1[i]+a^2*c)*t 上式を次のようなプログラムで表したのですが、出力される値が全て0になってしまいます。 もし原因が分かる方が居られましたらよろしくお願いします。 #include <stdio.h> int main(void) { double x1i = 0.0,x2i = 0.0; /*x1[i] x2[i]*/ double xa,xb; /*x1[i+1] x2[i+1]*/ double a; double b; double t = 0.05; double c = 1.0; scanf("%f" ,&a); scanf("%f", &b); while(t < 20){ xa = x1i + x2i * t; xb = x2i + ((-2 * b * a * x2i) - (a * a * x1i) + a * a * c) * t; x1i = xa; x2i = xb; t += 0.05; printf("%lf %lf \n", x1i,t); } return 0; }

  • モンテカルロ法の面積近似

    Mが2の32乗の、線形合同法で乱数を発生し、 モンテカルロ法を使って、 領域a = {(x,y)|x≧1,y≧2,(x-1)^2 + (y-2)^2 ≦1}の面積の近似値を計算するプログラムを作成し、これを利用してn=10000とした場合の上の領域の面積、および円周率πの近似値を求めよ。 (関数を使う) という課題が出たのですが、乱数の出し方?が変であまり近似されません(^_^;) どなたかどこが変か教えてください(>_<) これだと、2と4になってしまうんです(/_;) #include<stdio.h> #include<stdlib.h> #include<math.h> #define N 100 /*領域Rを含む面積T 領域R=求める面積*/ #define Nx 1 #define Ny 2 /*乱数を発生させる関数*/ unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c); int main(){ unsigned long int x0, a, c, M; double x, y, s; int n, count_in, count_out; count_in = 0; count_out = 0; printf("x0: ", x0 ); scanf("%d", &x0); a = 61; c = 49; for(n = 0; n < 10000; n++){ /*乱数を発生*/ x = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Nx + 1; y = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Ny + 1; if(x >= 1 && y >= 1 && pow(x-1, 2) + pow(y-2, 2) <= 1) count_in++; else count_out++; } s = (double)count_in/(count_in + count_out)*Nx*Ny; printf("s = %f\n", s); printf("pi = %f\n", 2*s); return 0; } unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c){ int i; x0 = (a*x0 + c); /*printf("%u\n", x0);*/ return x0; }

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

    プログラムの実行ができません。 どこを直したらよいのか教えて下さい。 よろしくお願いします。 #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); }

  • 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; } 分かる方がいましたら、回答よろしくお願いします。

  • C言語のプログラムに関することで質問です。

    C言語のライブラリを利用したプログラムのことで質問なのですが、座標xとyの成分から、ベクトルの角度(t)と大きさ(r)を求めるプログラムを作りました。しかし、このままのプログラムだと、ある場合のときに限り、正しい値が返されなくなるらしいのですが、それはどのような場合で正しい値が返されなくなってしまうのかを教えてください。また、正しい値がでるようにするにはどこをどう直したらよいのでしょうか? 自分でも考えてみたのですが、分からず困っています。分かる方どうかよろしくお願いいたします。 #include <stdio.h> #include <stdlib.h> #include <math.h> #define square(x) ((x) * (x)) //ベクトルの角度θを返す関数 double theta(double x, double y) { return atan(y / x); } //ベクトルの大きさを返す関数 double radius(double x, double y) { return sqrt(square(x) + square(y)); } int main(int argc, char **argv) { double x, y; //x, yは座標 double t, r; //t, rは極座標 if(argc == 3 && (x = atof(argv[1])) && (y = atof(argv[2]))) { t = theta(x, y);  //極座標tを計算 r = radius(x, y); //極座標rを計算   //ベクトルの角度と大きさを表示 printf("t = %f, r = %f\n", t, r); } return 0; }

  • モンテカルロ法を用いた実験

    モンテカルロ法を用いてy=x^2とx軸で囲まれた部分の面積の近似値を求める.これを利用して平均μ,標準偏差σ,を求めたところ下記の写真のようになった.点数nに対して標準偏差は何次であるかを,中心極限定理から求められる次数,実験結果から導かれる次数のそれぞれで求めなさい.次数とはどのように求められるのでしょうか?使用したプログラムを下に書いておきます. #include <stdio.h> #include <time.h> #include <stdlib.h> #include <math.h> double f(double x); int main(void) { int M = 1000; int i,j,n,c,k; int tmp[6] = { 20, 50, 100, 200, 500, 1000 }; double x,y,Y, sumY, sumY2, muY, muY2, sigmaY; srand((unsigned int)time(NULL)); for (k = 0; k < 6; k++){ sumY = 0; sumY2 = 0; for (j = 0; j < M; j++){ c = 0; n = tmp[k]; for (i = 0; i < n; i++){ x = (1.0* (double)rand()) / ((double)RAND_MAX + 1.0); y = (1.0* (double)rand()) / ((double)RAND_MAX + 1.0); if (y <= f(x)){ c++; } } Y = ((double)c) / (double)n; sumY = sumY + Y; sumY2 += Y*Y; } muY = sumY / (double)M; muY2 =sumY2 / (double)M; sigmaY = sqrt(muY2 -(muY*muY)); printf("%d %lf %lf\n", n, muY, sigmaY); } return 0; } double f(double x) { double r = x * x; return r; }

  • invalid operandsb to binary/エラー

    はじめましてこんにちは。 プログラミングでC言語を使っています。 y'=x^2sqrt(y)についてオイラー法で解くプログラミングを作成しているんですが,invalid operandsb to binaryとエラーが出てなかなかできません。 そのプログラミングが下に表すものなんですが /*euler2.c*/ /* オイラー法 */ /* y'=x^2*sqrt(y) */ #include <stdio.h> #include <math.h> int main() { int i; int N=10000; /* 区間の分割数 */ double a=0.0,b=2.0; /* 区間の指定([0,2]) */ double y0=1; /* 初期値 */ double x,y,h; h=(b-a)/N; /* 刻み幅の計算 */ x=a; y=y0; /* 初期条件 */ for (i=0;i<N;i++){ ★ y=y+x^2*sqrt(y)*h+(2*x*sqrt(y)+x^4/2)/2*h^2; x=x+h; printf("%g %g\n",x,y); } return 0; } ★印のあるL21にエラーが出ます。もしどこを直せばよいかわかる方お願いします。 プログラミング初心者のため、不適切な言葉等ありましたらすいません。

  • C言語の関数に関する質問ですが

    C言語の初心者です。よろしくお願いいたします。 授業でこのような演習が出ました。 演習:実数x を入力したときの最大値を求めるプログラムを作れ. 実数x を入力すると,x; -x; x2; xの絶対値の平方根 の中で一番大きい値を答える プログラムを作れ(ファイル名はmax.c とする). 表示は以下のようにする. Input x: -0.5 【Enter】 Answer is 0.707107. #include<stdio.h> #include<math.h> double max(double a, double b){ if( a > b) return a; else return b; } int main(void) { double x,y; printf(\"Input x: \"); scanf(\"%lf\",&x); y = max (x,-x); y = max (y,x*x); y = max (y,sqrt(fabs(x))); printf(\"Answer is %f.\\n\",y); } このように書けばうまく実行できますが、関数の中に関数を使えないでしょうか。うまく言えないですが、たとえば、以下のように書いてみましたが、うまく実行できません。どう直したらいいでしょうか、お忙しい中教えていただけたらうれしいです。 #include <stdio.h> #include <math.h> int max(double a,double b) { if (a<b) return b; else return a;} int main(void) { double x,result; printf(\"Input x:\"); scanf(\"%lf\",&x); result=max(max(x,-x),max(pow(x,2),sqrt(fabs(x)))); printf(\"%.2f\",result); return 0; } よろしくお願いいたします!!

  • sinの値を求めるプログラムでお聞きします。

    cos(x)の値をcosのテーラー展開の式から求めるプログラムを作り、無限級数の項の絶対値が0.00001以下になったら打ち切って、コンピュータで定義されるcos(x)の値との差を 0.0≦x≦0.1 の範囲で0.01刻みに求めよ。ただし、結果はファイルに書き出すこと。 という問いがあり、プログラムは下記のようなものだったのですが、 #include <stdio.h> #include <math.h> double COS(double x); int main(void) { double a; FILE *fout; fout=fopen("file1.txt","w"); for(a=0;a<0.1;a=a+0.01) { fprintf(fout,"a=%f COS=%e cos=%e error=%e\n",a,COS(a),cos(a),COS(a)-cos(a)); } return 0; } double COS(double x) { double t; double y; int n; y=1.0; t=1.0; n=1; while(1) { t=-t*x*x/((2*n)*(2*n-1)); if(fabs(t)<=0.00001) break; y=y+t; n++; } return y; } これが、例えば、cos(x)ではなくsin(x)についてだった場合、上記の最初に書いてある条件もまったく同じでプログラムを作ったとすると、上記のプログラムのどこどのように変えればいいのでしょうか。 分からなくて困っています。助けてください。