• 締切済み

ニュートン法をC言語でプログラム

方程式 cos^2x-0.5=0 (0<x<π) の解をニュートン法で求める という問題をC言語のプログラムを作り計算したいのですが分かりません。 自分で考えてみたプログラムは以下の通りです。 #include <stdio.h> #include <math.h> #define f1(x) cos(x)*cos(x)-0.5 #define f2(x) sin(2*x) /* ニュートン法による方程式の解 */ main() { double x0,x1,a,b,c,d,g,n; a=1; x0=0.7; n=0; while(a>0.0001){ b=x0; d=f1(b); g=f2(b); x1=x0-d/g; c=x1; a=f1(c); n=n+1; printf(" n= %f x1=%f x0=%f\n",n,x1,x0); printf(" a= %f → 解 x= %f \n", a,x1); x0=x1; } } 自分としてはこれが精一杯で、何故間違ってるのか、何をどうすればいいのか、さっぱり分かりません。どういったところが間違ってるのか可能性だけでも示して頂ければ幸いです。 参考として、ニュートン法によるプログラム例として書かれていたものを上げさせて頂きます。 例: e^x-3=0 の解をニュートン法により計算する。 #include <stdio.h> #include <math.h> #define f1(x) exp(x)-3 #define f2(x) exp(x) /* ニュートン法による方程式の解 */ main() { double x0,x1,e,a,b,c,d,g,n; a=1; x0=3; n=0; while(a>0.0001){ b=x0; d=f1(b); g=f2(b); x1=x0-d/g; c=x1; a=f1(c); n=n+1; printf(" n= %f x1=%f x0=%f\n",n,x1,x0); printf(" a= %f → 解  x= %f \n", a,x1); x0=x1; } }

みんなの回答

回答No.6

>正常には作動しているのですが >範囲がおかしいのか1回しか計算されない そうですか? 初期値x0に解の近傍の0.7与えているんで1回しか計算されなくてもしょーがない、とか思うんですけどね。 一般に、ニュートン法は収束までのステップ数は短いんで、当然だ、と思いますよ。 それより、問題は収束判定の a>0.0001 の方だと思います。これがaが負になった場合、対処してない、って思うんですが。 例えば、計算でf1(c)=-2000何とやら、となった場合、そこで計算が止まってしまいます。これは要求仕様じゃないでしょ? 多分、やりたかったのはaの絶対値>0.0001だと踏んでるんですが、それがコードに反映されていません。問題の性質から言うと、初期値はπの付近(例えば3.0とか)からスタートしても解を返さなきゃならない筈、なんですが、元々のコードを微分の部分だけ手直ししたら、おかしな解が出てくるんじゃないのかな、って思います。 その辺、ちょっと見てみてください。

19830617
質問者

お礼

0.7だから1回しかされないのと絶対値にするの分かりました。ありがとうございました。

  • orcus0930
  • ベストアンサー率41% (62/149)
回答No.5

f(x) = (cos(x))^2 - 0.5の微分は、 f'(x) = -sin(2x)ですね。 あと、引数の代入で、double型に代入するときは a=1; ではなく、 a=1.0; とするほうが無難でしょう。 あなたのプログラムをちょっと修正するだけで、正常作動することは、私のPCで確認できました。

19830617
質問者

お礼

回答ありがとうございました。 正常には作動しているのですが 範囲がおかしいのか1回しか計算されないので プログラムで計算させる意味がない事になってしまいました。

  • R_Earl
  • ベストアンサー率55% (473/849)
回答No.4

> (sin^2x)' > =2(sinx)(sinx)' > =2sinx*cosx > =sin(2X) > > となると思ったのですが… > よろしければ微分の何が違ってるかご指摘下さい。お願いします。 微分される関数はcos^2x - 0.5ですよね? なぜsin^2xの微分をしているのでしょうか? (cos^2x - 0.5)' = (cosx)(-sinx) = -(sinx)(cosx) = -sin2x となります。

19830617
質問者

お礼

何度もありがとうございます。 焦って違う問題の計算メモを書いてしまいました。 すみません。 マイナスがなかったのも自分の字が汚かっただけのようです。 ご丁寧にありがとうございました。

  • ushioni
  • ベストアンサー率24% (14/58)
回答No.3

回答ではなく、Cの書き方のアドバイスですが、 #define f2(x) sin(2*x) は #define f2(x) sin(2*(x)) と書いたほうが良いです。 理由は、 f2(PI/2)とf2(0+PI/2)をprintfしてみると分かります。

19830617
質問者

お礼

ご指摘ありがとうございます。 直してみます。

回答No.2

Cのマナーの部分と、数学の部分と、2つありますね。 Cの部分: 1:書き出しはmain()じゃなくってint main(void)にした方が良い。 これはツマラない部分ですし、計算結果は同じですが、「Cのマナー」としては、引数を取らないmain関数では引数はvoid、とした方が良い、です。 また、main関数の返り値自体も厳密に言うと、「計算結果とは別にして」OSに対して整数が返されます。従って、 2:正常にプログラムが終了した事を伝える為、返り値を返すように必ず最後にreturn 0;を付ける。 これもマナーです。計算結果を別にOSに「正常終了したよ~~。」と教える為、return 0;も必ず記述するようにしましょう。 数学の部分: #1さんも仰っている通り、(cos(x))^2-0.5の微分はsin(2*x)になりません。計算ミス、ですね。 プログラムは「言われた通りに計算してる」だけですんで、与えた微分係数が間違ってても感知せずに、「言われた通りに計算している」だけです。 特に、コンパイル時にエラーが出ないで正常実行出来るCによるプログラムの場合、プログラムの記法自体にはさほど問題が見られません。つまり、こう言うケースでは「プログラムを記述した人間が」何かミスをした、って事ですね。 このソースも微分係数をキチンと書き換えれば、そのままキチンとした計算結果を返してくれました。つまり、全体としてのロジックは全然間違ってなく、単に「与えた微分係数が間違ってた」ってだけですね。

19830617
質問者

お礼

回答ありがとうございます。 Cのマナーについてですが、今このように授業で習っているのでその先生に対して違う書き方でプログラムを書いて出すことは出来ないのでどうかそこは見逃して下さい。一応、cametan_42がおっしゃられている書き方が基本だと理解してはいるのですが…。

  • koko_u_u
  • ベストアンサー率18% (216/1139)
回答No.1

微分がまちがっている。

19830617
質問者

お礼

さっそく回答ありがとうございます (sin^2x)' =2(sinx)(sinx)' =2sinx*cosx =sin(2X) となると思ったのですが… よろしければ微分の何が違ってるかご指摘下さい。お願いします。

関連するQ&A

  • ニュートン法を使って解を求めるC言語プログラム

    C言語を使って y=x^2-4x のyの解をニュートン法を使って求める プログラムを作る課題を出されたんですが、ニュートン法が良く分かっていないので、いろいろ調べたり、人に聞いたりしたところ #include<stdio.h> #include<math.h> void main() { int counter=0; double an,g,f,sh=0.0001; printf("初期値を入力して下さい==>"); scanf("%ld",&an); do{ g=(an*an)/(2*an-4); f=2*an-4; counter++; }while(fabs(f)>sh); printf("反復回数 %d 回 y=%lf \n",counter,g); } でプログラムがこんな感じになったんですが、結局ニュートン法がどうなのかがわかりません。 なんか微分とかやるとか言われたんですが、工業系の学校で数学の授業が無いので微分についてがわかりません。 このプログラムは、コンパイルはできるんですが、動きません。 ニュートン法についてよくわからないのでどこが間違ってるかわかりません。 ニュートン法についてできるだけ分かりやすく解説してほしいです。

  • c言語 プログラミング(初心者)

    解を判定するプログラミングを作成したのですが、a,b,cを0,1,2と入力したときに解に0.00000が出てきて解がおかしくなります。 どなたか詳しい方教えてください。また簡潔にできる点などありましたらご指摘お願いします。 #include <stdio.h> #include <math.h> int main (void) { double a,b,c,d,x1,x2; printf("ax^2+bx+c=0 の係数を入力してください\n"); scanf("%lf %lf %lf",&a,&b,&c ); if(a==0){ if(b==0) { printf("解は存在しません\n"); } else { x1=-c/b; printf("解は %f です\n",x1); } } else { d=b*b-4*a*c; if(d>=0){ x1=(-b+sqrt(d))/(2.0*a); x2=(-b-sqrt(d))/(2.0*a); if(d==0){ printf("解は %f (重解)です\n",x1); } else { printf("解は %f と %f です\n",x1,x2); } } else { printf("実数解は存在しません(虚数解)\n"); } } return 0; }

  • C++でのプログラムについての質問です

    このような二次関数の解を求めるプログラムを作成したのですが、自作関数solveをvoid solve(double, double, double)のように変更し同じ動作をするように変更したいです どのようにへんこうすればよいでしょうか #include<stdio.h> #include<stdlib.h> #include<math.h> int main(void) { double a, b, c; /*二次方程式の定数*/ double D, x1, x2, r1, r2; printf("ax^2 + bx + c = 0 の係数 a, b, c を入力してください---> \n"); scanf_s("%lf %lf %lf", &a, &b, &c); printf("2次方程式を解いた結果は次の通りとなる。\n"); if (a == 0.0) { if (b == 0.0) { printf("係数がおかしい\n"); exit(-1); } { x1 = -c / b; printf("解は%f です。\n", x1); exit(0); } } else { D = b * b - 4 * a * c; if (D >= 0) { x1 = (-b + sqrt(D)) / (2.0 * a); x2 = (-b - sqrt(D)) / (2.0 * a); if (D == 0.0) { printf("解は %f です。\n", x1); } else { printf("解は %f と %f です。¥n", x1, x2); } } else { r1 = -b / (2 * a); r2 = sqrt(-D) / (2 * a); printf("解は%.2f+%.2fi と%.2f-%.2fi \n", r1, r2, r1, r2); } } return 0; }

  • C言語についての質問です

    プログラミング初心者です if関数を使用して二次方程式の解を解くプログムを作成したのですが、この作成した関数をユーザー定義関数を使用しmain 関数の中でユーザー定義関数を呼び出すことにより、 2次方程式の解を求めるプログラムへ変更したいのですが、どのように行えばいいのか分かりません… 私が作成したプログラムはこのようなものになっています #include<stdio.h> #include<stdlib.h> #include<math.h> int main(void) { double a, b, c; /*二次方程式の定数*/ double D, x1, x2, r1, r2; printf("ax^2 + bx + c = 0 の係数 a, b, c を入力してください---> \n"); scanf_s("%lf %lf %lf", &a, &b, &c); printf("2次方程式を解いた結果は次の通りとなる。\n"); if (a == 0.0) { if (b == 0.0) { printf("係数がおかしい\n"); exit(-1); } { x1 = -c / b; printf("解は%f です。\n", x1); exit(0); } } else { D = b * b - 4 * a * c; if (D >= 0) { x1 = (-b + sqrt(D)) / (2.0 * a); x2 = (-b - sqrt(D)) / (2.0 * a); if (D == 0.0) { printf("解は %f です。\n", x1); } else { printf("解は %f と %f です。¥n", x1, x2); } } else { r1 = -b / (2 * a); r2 = sqrt(-D) / (2 * a); printf("解は%.2f+%.2fi と%.2f-%.2fi \n", r1, r2, r1, r2); } } return 0; } よろしくお願いいたします

  • ニュートン法

    ケプラー方程式x-e*sin(x)-c=0の解をステップ数とともに出力するプログラムで、e,cはそれぞれ0.5と1です。 xに値を入力して計算させるのですが、どうしてもできません。 下のプログラムリストでおかしいところはどこでしょうか? // ニュートン法 x-e*sin(x)-c=0 #include <stdio.h> #include <math.h> #define e 0.5 #define c 1.0 #define K 10000 double fun(double x); double bibun(int i,double x); float m=1.0,n=1.0; int i=1; main(){ float x1,x2; float z; printf("初期値x0を入力して下さい\n"); scanf("%f",&x1); for(i=0;i<=K;i++){ x2 = x1 - fun(x1)/bibun(i,x1); x1 = x2; z = fun(x1); z = fabs(z); if(fabs(z)<=0.00001){ break; } if(i==K){ printf("収束しません\n"); exit(0); }    } printf("解 = %f\n",x1); printf("ステップ数 = %d",i); return 0; } // 関数f(x) double fun(double x1){ double r; r = x1 - e * sin(x1) - c; return r; } // 微分 double bibun(int i,double x1){ float p; if(i%2==1){ p = pow((-1.0),m)*e*sin(x1); m++; } else { p = pow((-1.0),n)*e*cos(x1); n++; } return p; }

  • C言語プログラム(二分法)について質問です。

    C言語プログラム(二分法)について質問です。 以下作成したプログラムでは、aを入力すると, x=b - (log(a)) - (a+x)/2の解が求まります。(今回式は適当ですが。) 二分法で解を求めるというプログラムは作成できたのですが、 このプログラムで、aを1~10まで変化させたときのxの値というようなループをプログラムでしたうえで、 a*xの値がもっとも大い点を求めるためにはどのようなプログラムを組めば(これを改良すれば)いいのでしょうか? 具体的に行いたいことは、この二分法のプログラムをaとxの関数とし、a*xの最大点を求めたいのです。 質問が分かりにくいかもしれませんが、お願いします。 以下作成したプログラムです。 #include <stdio.h> #include <stdlib.h> #include <math.h> #define eps 1.0e-6 double b=0.3; double a=0; double f(double x); void nibun(void); int main() { nibun(); return 0; } void nibun(void) { int count; double x0,x1,m; printf("aの値\n"); scanf("%lf",&a); count=0; x0=-2*b; x1=b; do { count++; m=(x0+x1)/2.0; if(f(m)*f(x0)<0) x1=m; else x0=m; if(count==700) { printf("Error\n"); exit(1); } } while (!(fabs(x0-x1)<eps)); printf("解の値は %f\n",m); } double f(double x) { return(b - (log(a)) - (a+x)/2); }

  • c言語です。

    c言語です。 実行結果 式 3 X1 + 2 X2 + 1 X3 = &g 2 X1 + 5 X2 + 2 X3 = &g 1 X1 + 4 X2 + 1 X3 = &g 解 X1 = 1 X2 = 2 X3 = 3 を 式 3 X1 + 2 X2 + 1 X3 = 10 2 X1 + 5 X2 + 2 X3 = 18 1 X1 + 4 X2 + 1 X3 = 12 解 X1 = 1 X2 = 2 X3 = 3 に直したいのですが&gの所をどのようにしたら10.18.12になりますか? #include <stdio.h> #include <float.h> #define N 3 double A[N][N] = {{3,2,1}, {2,5,2}, {1,4,1}}; double b[N] = { 10, 18, 12 }; void Gauss_J( int, double*, double* ); void main(void) { int i; printf( "%d式\n", N ); for( i = 0; i < N ; i++ ) { printf( "%g X1 + %g X2 + %g X3 = &g \n", A[i][0], A[i][1], A[i][2], b[i] ); } printf("解\n"); Gauss_J(N, (double *)A, (double *)b ); printf("X1 = %g \n", b[0]); printf("X2 = %g \n", b[1]); printf("X3 = %g \n", b[2]); } void Gauss_J(int n, double *a, double *b) { int p, i, j,I ; double pivot, c ; for ( p = 0 ; p < n ; p++ ) { pivot = a[ p*n + p ]; for ( i = p ; i < n ; i++ ) { a[ p*n + i ] /= pivot; } b[ p ] /= pivot; for ( I = 0 ; I < n ; I++) { if (I != p) { c = a[ I*n + p]; for ( j = p ; j < n; j++ ) { a[ I*n + j] -= c * a[ p*n + j ]; } b[ I ] -= c * b[ p ]; } } } return ; }

  • C言語 ニュートン法

    何をすればいいかよくわからなくて躓きました わかる方どうかお願いします 問 以下に示すプログラムで、x1 = x0 - f (x0) / f '(x0)を用いて、方程式の左辺関数 f (x) (= x 2 - a ) およびその導関数 f '(x) を独立させろ。 入力変数 a はグローバル変数としてよい。 導関数 f '(x)はプログラム内ではdfと表記することとする。 また、適切なコメントも追加すること。 /* newton.c: ニュートン法 */ #include <stdio.h> // printf, fprintf, fgets, sscanf #include <math.h> // fabs double newton(double x, double (*f)(double), double (*df)(double), double eps) {   int n;   double a = 0, x, x0, err, eps = 1.0e-10;   printf("# n, x, err\n");   printf("%4d, % .15e\n", n, x);   do {     n++;     x0 = x;     x = (x0 + a/x0) / 2;     err = fabs(x-x0);     printf("%4d, % .8e, % .8e\n", n, x, err);   } while (err > eps);     return x; } int main(void) {    double a = 0, x, x0, err, eps = 1.0e-10;    char s[128];   fprintf(stderr, " a = "); fgets(s, 128, stdin); sscanf(s, "%lf", &a);   while (a <= 0.0) {    fprintf(stderr, "'a' には正の数を入れてください。\n");   fprintf(stderr, " a = "); fgets(s, 128, stdin); sscanf(s, "%lf", &a);   }   x = (a + 1.0) / 2.0;   printf("\n# sqrt(%e) = % .15e\n", a, x);    return 0; }

  • 2次方程式の解 Cプログラミング

    C言語でのプログラムの添削をお願いします。 2次方程式の解を求めるものなのですが。 #include<stdio.h> #include<math.h> main(){ double a,b,c,d; double x1=0; double x2=0; scanf("%lf %lf %lf" ,&a,&b,&c); printf("a=%f b=%f c=%f\n" ,a,b,c); d=b*b-4*a*c; if(d>0){ x1=(-b+sqrt(d))/2*a; x2=(-b-sqrt(d))/2*a; printf("x=%f,%f\n" ,x1,x2); }else if(d<0){ x1=-b/2*a; x2=sqrt(-d)/2*a; printf("x=%f+%fi,%f-%fi\n" ,x1,x2,x1,x2); }else{ printf("x=%f\n" ,x1); } return 0; } このとき、 a=-7,b=2,c=-1 を与えると x=7.000000+-17.146428i,7.000000--17.146428i という値が返ってきます。 他にも、虚数解のときに間違った値が返ってきてしまう気がするのですが、いかがでしょうか? 実数解のときは正しいようです。 回答よろしくお願いします。

  • ニュートン法のプログラムの問題です。

    ニュートン法のプログラムを書き換える問題なのですが、考えたものを実行してみても上手く値が求められなかったので質問させてください。 ・問題 ニュートン法でbのn乗根を求めるプログラムです。 これを、bを与えたときx/(x^2+1)=bとなるxを求めるプログラムに書き換えなさい。 10 input "n,b";n,b 20 x=1 30 f=x^n-b 40 d1=n*x^(n-1) 50 x1=x-f/d1 60 e=1*10^(-6) 70 if abs(f)<e then goto 100 80 x=x1 85 print x 90 goto 30 100 end 考えたものとしては、 f(x) = x^n - b を f(x) = x/(x^2 + 1) - b に、 d1(x) = n*x^(n - 1) を d1(x) = 1/(x^2 + 1) - 2*x^2*/((x^2 + 1)^2)に 改変するという方法だったんですが… 考え方とどのように改変すればこの値が求められるのか、わかる方教えてください! ちょっと急ぎなのでできれば簡潔に書いていただけると助かります… よろしくお願いします!