はさみうち法のプログラム(C言語)について

このQ&Aのポイント
  • C言語で作成したはさみうち法のプログラムがうまく動作しない問題について
  • プログラムの実行結果が期待通りの値ではなく「nan」となってしまう
  • 修正すべき箇所や解決策について教えてください
回答を見る
  • ベストアンサー

はさみうち法のプログラム(C言語)について

調べたりしながら私なりに書いてみたのですが上手くいきません。 「ans=1.048404」とならなければいけないのに 「nan」で返ってきてしまうのです。 どこをどの様に変えたら良いのでしょうか・・・? ※課題の締め切りが近いので,早急にご回答宜しくお願い致します! 以下、はさみうちのプログラム↓ #include<stdio.h> #include<math.h> /*初期値x0,*/ /*f(x)を定義*/ double f(double x){ return sqrt(x*x+10.0) - 10.0*exp(-x*x); } /*はさみうち法の関数*/ double hasamiuchi(double x0,double x1,double eps,double imax){ double x2; /*x軸との交点*/ int i; /*繰り返しの回数*/ if(f(x0)*f(x1)>0){/*x0とx1が同符号の場合x1をx0とする*/ x0=x1; } for(i=0;i<imax;i++){ x2=(x1*f(x0)-x0*f(x1))/(f(x0)-f(x1)); /*x0とx1で出来る直線とx軸の交点x2を求める*/ x1=x2; /*x2の値を次のループにおけるx1とする*/ } if(fabs(x1-x0)<eps) return x2; /*収束したら解x2を返す*/ return 0.0/0.0; /*収束しなかったらnanを返す*/ } int main(void){ printf("ans = %f\n", hasamiuchi(2.0,1.0,1e-6,20));/*値を代入してはさみうちの実行*/ return 0; }

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

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.5

問題の箇所を質問文のプログラムでズバリ言うと if(fabs(x1-x0)<eps) return x2; /*収束したら解x2を返す*/ この行だ。 はさみうち法は2つ方法があって、それぞれ何が何に収束していくかが違う。 両方が移動する方法と片方が移動する方法で、前者は2点の距離が0に、後者は移動する方の点x'におけるf(x')が0に収束する。で、あなたのプログラムは計算ロジックは後者なのに収束判定に前者のものを使っている。 ~~~~~~ 余談ではあるけど、移動するのは片方だけでいいんだけど、どっちを移動させるかは自動でより適切な方が選ばれるようにした方が良いだろう。あなたのプログラムは、x1が移動する方だと20回では1e-6以内に収まらない。x0の方だと5回目で0.000000に収束する。

aicyan7
質問者

お礼

なるほど!! 簡潔でとても分かりやすかったです! ありがとうございました!

その他の回答 (4)

  • f272
  • ベストアンサー率46% (7994/17083)
回答No.4

http://www-it.sci.waseda.ac.jp/teachers/w405201/OLD/CPR2-2010/cprogram10.pdf これのリスト26 falseposition.cでは if ( fx*f0 > 0 ) x0 = xp; と書いてあるよね。 また収束の判定についても if ( fabs(x-xp) < DBL_EPSILON || fabs(fx) < DBL_EPSILON ) break; となってるよね。

  • hashioogi
  • ベストアンサー率25% (102/404)
回答No.3

求める点はどこだかわからないけど決まっている。 その点を二人の人がいて一人は上から下へ、もう一人の人が下から上へ追い込んで行って、二人の距離が十分小さくなったときに挟み込めたと判断するのが挟み込みだと思うが、プログラムを見ると片方の人(x1)しか移動していない。これだとx0が移動していないからいつになっても挟み込めない。と思う。

aicyan7
質問者

お礼

なるほど! 確かにそうですね!! ご指摘,ありがとうございます

回答No.2

初期値 : x0, x1 (x0 < x1) の範囲で f(x) == 0 となるxを求める [1] xm = (x0 + x1) /2 [2.0] x1-x0 が十分小さければ xm が解である → おわり [2.1] 解が x0 と xm の間にあるならば x1 = xm [2.2] 解が xm と x1 の間にあるならば x0 = xm [2.3] どちらでもなければ失敗 → おわり [3] [1]に戻る

aicyan7
質問者

補足

ご回答ありがとうございます ですが,[1]の式を使って方程式の解を求めるのは,二分法の時だけでなく, はさみうちもなのでしょうか・・・?

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

「はさみうち法」の原理は理解できていますか?

aicyan7
質問者

補足

http://www-it.sci.waseda.ac.jp/teachers/w405201/OLD/CPR2-2010/cprogram10.pdf http://shiotani.cn/shiotanicnb4a/20111212cpptwo.html 以上の2つのページを基に  (1)x0を基準点として既定のx1とx0を通る直線を考える  (2)(1)の直線とx軸とが交わる点を次のx1とする  (3)|x1-x0|<εとなるまで(1)(2)を繰り返す   |x1-x0|<εとなる時,x1が解 と考えるのかなと思っていました。 解釈が違っているのかもしれません・・・ どの様に考えれば良いのか教えていただけませんか?

関連するQ&A

  • C言語 二分法

    初投稿です。 お恥ずかしながらパソコンが苦手で、Cゲッが難しくてできません。 今回二分法です。 途中まではやったのですができません。 演習 0~1の乱数を12個発生させ,これらの平均をxi,yi とする。(s,tは乱数) xi=1/12(x1i+x2i+....x12i) yi=1/12(y1i+y2i+....y12i) このようなを1000個作り,(xi,yi)で散布図 を作りなさい。またx,yのそれぞれの平均を求 めよ。 この演習で #include<stdio.h> #include<stdlib.h> #include<math.h> #define eps 1.0e-5 float f(double x); void nibuin(void); int main () { int count; double a,b,m; count=0; printf("範囲の左の値を入力してください。\n"); scanf("%lf",&a); printf("範囲の右の値を入力してください。\n"); scanf("%lf",&a); if(count==1000){ printf("収束しませんでした。\n"); exit(1); } } while(!(fabs(a-b)<eps)); printf("解の値は%f\n収束するのに%d回かかりました。"m,count); } float f(double x) { reurn x*sin(x)+log(x); } まではできたのですが、 scanf("%lf",&a);とif(count==1000){の間に入る命令が打てません。 よろしくお願いします。

  • 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プログラムについて

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

  • C言語課題(数値計算)お願いします。

    課題内容 ニュートン法を用いて√2の値を求められるプログラムを作る。 10ケタまで表示する。 書いてみたソースコード #include <stdio.h> #include <stdlib.h> #include <math.h> #define max 1000 //最大繰り返し回数 #define eps 1.0e-10 //収束条件 double f(double x); double df(double x); void newton(void); int main() { newton(); return 0; } void newton(void) { int count; double a,newa; count=0; printf("初期値を入力してください。\n"); scanf("%lf",&a); for(;;) { count++; newa=a-f(a)/df(a); if(fabs(newa-a)<eps) break; a=newa; if(count==max) { printf("収束しませんでした。\n"); exit(1); } } printf("解の値は %f\n収束するのに %d 回かかりました。\n", newa,count); } double f(double x) { return x*x-2; } double df(double x) { return 2x; } コンパイルできません。 間違いとどうすればよいかを教えていただけるとありがたいです!!!

  • C言語の質問です

    ニュートン法のプログラムを組んだのですがPAD図が描けなくて困ってます どなたか回答お願いします /* newton.c: ニュートン法 */ #include <stdio.h> // printf, fprintf, fgets, sscanf #include <math.h> // fabs double a;    //グローバル変数 double f(double x)  //fは関数f(x) { return x * x - a; //f(x)=x~2-a } double df(double x)  //dfはf(x)の導関数f’(x) { return 2 * x; //df(x)/dx = 2x } double newton(double x, double (*f)(double), double (*df)(double), double eps) { int n = 0;     //初期化 double x0, err;    //x0は初期値 printf("# n, x, err\n"); printf("%4d, % .15e\n", n, x); do { n++; x0 = x; x = x0 - f(x0) / df(x0); //切片でy=0、x=x1 err = fabs(x-x0); printf("%4d, % .8e, % .15e\n", n, x, err); } while (err >= eps); return x; } /*メインルーチン*/ int main(void) { double x, 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; x = newton(x, f, df, eps);   //ニュートン法の実装 printf("\n# √(%e) = % .15e\n", a, x); return 0; }

  • 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; }

  • c言語プログラミングについて

    ニュートン法でx^2-2の根を初期値2、試行回数を200回までで求めるプログラムを作成しているのですがうまくいきません。 どなたかご教授お願いいたします。 #include<stdio.h> #include<math.h> int main() { int i; int N = 200; double x = 2.0; double xnew; double eps = 1e-16; for (i = 0; i < N; i++) { xnew = x - ( x * x - 2.0 ) / 2.0 * x; if (fabs(x - xnew) < eps) break; x = xnew; } printf("x=%.20lf\n", xnew); return(0); }

  • ニュートン法を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; } }

  • C言語プログラミング

    プログラミングについてです。 osはLinuxです。 x+logx=0の解を求めるプログラムを作れで ニュートン法を使ってみましたがあってますか? #include <stdio.h> #include <math.h> #define EPS 1e-8 main( ) { double a, old_x, new_x; int i; printf(" a="); scanf("%lf", &a); new_x = a; for(i=1; i<=100; i++) { old_x=new_x; new_x = old_x*(1-log(old_x))/(old_x+1); printf("x%d = %f\n", i,new_x); if(fabs(old_x*(1-log(old_x))/(old_x+1)) < EPS) break; } } いろいろな数字で実行してみた結果 nanと 0.567143の二つに分かれました。 どこか間違いがあるのですか

  • C言語のプログラム作成で・・・

    NaOH 濃度を入力すると、水酸化ナトリウム水溶液の pH を出力するプログラム(naoh.c)を作成せよ。 NaOH の解離度は、1.0 とし、Kw=1.0x10-14 [(mol/dm3)2] とする。 という問題でプログラムは #include <stdio.h> #include <math.h> main() { float fx,dfx,x,x0,eps,Kw,C,pH,x_an,pH_an; int i; Kw=1.0e-14; printf("x0="); scanf("%f",&x0); printf("C="); scanf("%f",&C); i=1; eps=fabs(x0*x0+C*x0-Kw); while ( eps > C/1e8 ) { fx=x0*x0+C*x0-Kw; dfx=2*x0+C; x = x0 - fx/dfx; eps=fabs(fx); printf("i=%3d fx=%.4e eps=%.4e x=%.4e\n",i,fx,eps,x); x0=x; i=i+1; } としました。そこで次に、濃度 Ca [mol/l] の塩酸 Va [ml]と濃度 Cb [mol/l] のNaOH水溶液 Vb [ml]を混ぜた溶液のpH を計算するプログラムを作成せよ。 という問題が出たのですがどうやって作成すればいいのでしょうか? HCl,NaOH の解離度は、1.0 とし、Kw=1.0x10-14 [(mol/dm3)2] とするらしいです。 めんどくさいと思いますがお願いします。