• 締切済み

ニュートン法

ケプラー方程式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; }

みんなの回答

  • koko_u
  • ベストアンサー率12% (14/116)
回答No.3

>koko_uさんの考えてるアルゴリズムはどのようなものですか? アルゴリズムはニュートン法なんでしょ。 どうもわかっておられないようなので、ひとまず初期値を 0 とか置いて、 x_0 = 0, x_1 = ◯, x_2 = △, ... と計算して下さい。 その後、計算が面倒なのでコンピュータにやらせるとしたらどうすればいいか考えましょう。

keikei07
質問者

お礼

わかりました。 新xについて、新f(x)を微分するということをやっていました。 ニュートン法自体をうまく把握できていなかったようです。 ありがとうございました。

noname#26650
noname#26650
回答No.2

サンプルです。 #include <stdio.h> #include <stdlib.h> #include <math.h> #define e (0.5) #define c (1.0) #define K (10000) #define EPS (0.00001) double f(double x); double g(double x); int main(void) {   double x1, x2;   int i;      printf("初期値x1を入力して下さい\n");   scanf("%lf", &x1);   for (i = 0; i < K; i++) {     x2 = x1 - f(x1) / g(x1);     if (fabs(x2 - x1) <= EPS)       break;     x1 = x2;   }   if (i < K) {     printf("解 = %f\n", x1);     printf("ステップ数 = %d\n", i);   }   else {     printf("収束しません\n");     exit(1);   }   return 0; } double f(double x) {   return x - e * sin(x) - c; } double g(double x) {   return 1 - e * cos(x); } (注)インデントのため、全角空白を使っています。

  • koko_u
  • ベストアンサー率12% (14/116)
回答No.1

とりあえず、double bibun(int i, double x1) がまったくわからん 1. 戻り値が double なのに何故か float p; 2. m, n が唐突に出現。 3. (-1)^m を求めようとして pow( -1.0, m ) としてるの?普通に場合分けじゃね? だいたい、ニュートン法って一階微分がわかれば x_(n+1) = x_n - f(x_n)/f'(x_n) でステップバイステップじゃないの? もっとややこしいことしようとしてるの?

keikei07
質問者

補足

x_(n+1) = x_n - f(x_n)/f'(x_n) でステップバイステップというのがよく分かりません。x_(n+1)を新たなx_nと考えて計算していくんですよね?そうするとsinとcosが交互に出てくると思って、こんな感じにしてしまったのですが。 koko_uさんの考えてるアルゴリズムはどのようなものですか?

関連するQ&A

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

    何をすればいいかよくわからなくて躓きました わかる方どうかお願いします 問 以下に示すプログラムで、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言語です。

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

  • 二分法のプログラム

    関数x^3-7x^2-6x+2を二分法で解くプログラムを作ったのですが、エラーが出てコンパイルできません。訂正箇所を教えて下さい。 宜しくお願い致します。 #include<stdio.h> #include<math.h> #define EPSILON 0.1E-5 #define TURE 1 #define FALSE 0 int kansu(int x); void Nibunho(left,right,sol,flag); double left,right; int flag; int main(void) { printf("区間の左端と右端は?\n"); scanf("%lf %lf",&left,&right); flag=FALSE; Nibunho(left,right,&root,&flag); if(flag) printf("解 = %e (繰り返し回数 = %d)\n",root,k); else { printf("入力した範囲で解は求まりませんでした。\n"); printf("f(%e) = %e \n",root,k); } return 0; } int kansu(int x) { int f(double x) f(x)=x*x*x-7.0*x*x-6.0*x+2.0; return(f(x)); } void Nibunho(left,right,sol,flag) { double left,right,*sol; int *flag; double a,b,c,fa,fb,fc; k=0; a=left; b=right; do { k++; c=(a+b)/2.0; fc=f(c); fa=f(a); fb=f(b); if(fabs(fc)<1.0e-10) { a=c; b=c; *flag=TRUE; } else { if( (fa * fc < 0.0) || (fb * fc < 0.0) ) { *flag = TRUE; if( (fa*fc) < 0.0 ) b=c; else a=c; } else { if( fabs(fa) > fabs(fb) ) a=c; else b=c; } } } while((b-a)>EPSILON) *sol=(a+b)/2.0; }

  • 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言語の勉強を最近始めたのですが、 以下のプログラムで教えていただきたい点があります。 #include <stdio.h> #include <math.h> #define x 10000 #define y 200000 #define z 1.0E-12 #define k 1.38 #define kE 1.0E-23 #define h 6.63 #define hE 1.0E-34 #define c 3.00 #define cE 1.0E+08 void main(void){ int i; double A[x+1]; double B[x+1]; for(i=0;i<=x;i++) { A[i]=(i+y)*z; B[i] = exp(-(h*hE*c*cE)/(A[i]*k*kE*1000)); printf("%e %e\n",A[i],B[i]); }} このプログラムで、xを100000にするとプログラムが動かなくなってしまいます。OSはWindowsXP、ソフトはVisual C++ 6.0を使っています。 解決方法を教えていただけないでしょうか。

  • このプログラムがうまく作動しないのですが・・・

    #include <stdio.h> #include <math.h> #include <stdlib.h> float f(float x); float f(float x) { return (float)(x-sin(x)/cos(x)); } void main() { float x1,x2,eps,f1,f2,xm,ff; int i; printf("Bisection method\n\n"); for(;scanf("%g%g%g",&x1,&x2,&eps)!=EOF;){ f1= f(x1); f2= f(x2); if(f1>0){ xm= x1; x1= x2; x2=xm; ff= f1; f1= f2; f2=ff; } printf("\nFinding a root between x1=%g and x2=%g\n", x1, x2); printf("f(x1)=%g f(x2)=%g eps=%g\n", f1, f2, eps); printf("\tx1\t\tx2\t\txm\t\tf(xm)\n"); if(f2<0){ printf("????\n"); continue; } i= 0; for(;fabs(x1-x2)>=eps;){ xm=(x1+x2)*((float)rand()/(float)RAND_MAX) ff= f(xm); i++; printf("%2d %15.6e %15.6e %15.6e %15.6e\n",i, x1, x2, xm, ff); if(ff<0) x1= xm; else x2= xm; } printf("A root found between %g and %g\n", x1, x2); } } f(x)=x-tanx=0の解のうち3つを表示させるためにランダムサーチのプログラムを上記のように書いたつもりなんですがうまく作動しません。どこをどう直したらいいのでしょうか、教えてください。

  • ランダムサーチ!!

    #include <stdio.h> #include <math.h> float f(float x); float f(float x) { return (float)(x-sin(x)/cos(x)); } void main() { float x1,x2,eps,f1,f2,xm,ff; int i; printf("Bisection method\n\n"); for(;scanf("%g%g%g",&x1,&x2,&eps)!=EOF;){ f1= f(x1); f2= f(x2); if(f1>0){ xm= x1; x1= x2; x2=xm; ff= f1; f1= f2; f2=ff; } printf("\nFinding a root between x1=%g and x2=%g\n", x1, x2); printf("f(x1)=%g f(x2)=%g eps=%g\n", f1, f2, eps); printf("\tx1\t\tx2\t\txm\t\tf(xm)\n"); if(f2<0){ printf("????\n"); continue; } i= 0; for(;fabs(x1-x2)>=eps;){ xm= (x1+x2)/2; ff= f(xm); i++; printf("%2d %15.6e %15.6e %15.6e %15.6e\n",i, x1, x2, xm, ff); if(ff<0) x1= xm; else x2= xm; } printf("A root found between %g and %g\n", x1, x2); } } 上のプログラムはf(x)=x-tanx=0の解のうち3つを表示するプログラムです。この方法をランダムサーチのプログラムと比較したいのですが、プログラムがうまく書けず悩んでいます。よろしければどちらがどのようなメリット、あるいはデメリットがあるのかも教えてほしいです。お願いします。

  • 掃出法で連立一次方程式の解を求める

    掃出法で連立一次方程式の解を求めるプログラムを作ってみたのですが、ポインタと浮動小数点のエラーが出てしまい、実行できません。どこが間違っているのかさえ分からず困っています。訂正箇所を教えてください。宜しくお願い致します。 #include<stdio.h> #include<math.h> #include <float.h> #define N 3 #define EPSILON 1.0E-5 #define TRUE 1 #define FALSE 0 void sweep(int *flag); void swap(float *wk1,float *wk2); float a[N][N]={{ 2, 6, 3}, {-1, 5,-2}, {-2,-1, 6}}; float x[N],b[N]={6,3,14}; int flag; void main() { int i,j; for(i=0;i<N;i++) { for(j=0;j<N;j++) printf("%10.4f",a[i][j]); printf("%10.4f\n",b[i]); } flag=TRUE; sweep(&flag); if(flag==TRUE) { printf("連立方程式の解\n"); for(i=0;i=N;i++) printf("x[%d]=%10.4f\n",i+1,x[i]); } else printf("解なし\n"); } void swap(float *wk1,float *wk2) { float w; w=*wk1; *wk1=*wk2; *wk2=w; } void sweep(int *flag) { int i,j,k,ik; float ak,aik; for(k=0;k<N;k++) { ak=a[k][k]; if(fabs(ak)<=EPSILON) { ik=k+1; while((ik<N)&&(fabs(a[ik][k])<EPSILON)) ik++; if(ik<N) { for(j=k;j<N;j++) swap(&a[k][j],&a[ik][j]); swap(b[k],b[ik]); ak=a[k][k]; } else { printf("ピボットが零です\n"); *flag=FALSE; goto end; } } for(j=k;j<N;j++) a[k][j]=a[k][j]/ak; b[k]=b[k]/ak; for(i=0;i<N;i++) { if(i!=k) { aik=a[i][k]; for(j=k;j<N;j++) a[k][j]=a[i][j]-aik*a[k][j]; b[i]=b[i]-aik*b[k]; } } for(k=0;k<N;k++) x[k]=b[k]; end:; } }

  • jacobiのNewton法

    何回やっても収束しません。 初期値は共に1.0でε(誤差)は0.001ぐらいで回数を1000にしてます。 答えがありえないぐらい大きくなったりします。 どこがちがうでしょうか?わかる方お願いします。 #include<stdio.h> #include<math.h> double xn[10][100],ipu,jacobi,gyou[2],gyouretu[2][2],a[2]; int genkai,i,j; void nyuryoku(void); double f(double,double); double g(double,double); double fx(double,double); double fy(double,double); double gx(double,double); double gy(double,double); void keisan(void); void syuturyoku(void); int main(void) { nyuryoku(); keisan(); syuturyoku(); exit(0); } void nyuryoku(void) { for(j=0;j<2;j++){ printf("初期値x,yを入力してください"); scanf("%lf",&xn[j][0]); } printf("εを入力してください。"); scanf("%lf",&ipu); printf("収束しないと判断する回数は?"); scanf("%d",&genkai); } void keisan(void) { for(i=0;i<genkai;i++){ gyouretu[0][0]=fx(xn[0][i],xn[1][i]); gyouretu[0][1]=fy(xn[0][i],xn[1][i]); gyouretu[1][0]=gx(xn[0][i],xn[1][i]); gyouretu[1][1]=gy(xn[0][i],xn[1][i]); a[0]=f(xn[0][i],xn[1][i]); a[1]=g(xn[0][i],xn[1][i]); gyou[0]=gyouretu[0][0]*a[0]+gyouretu[0][1]*a[1]; gyou[1]=gyouretu[1][0]*a[0]+gyouretu[1][1]*a[1]; jacobi=1/(gyouretu[1][1]*gyouretu[0][0]-gyouretu[0][1]*gyouretu[1][0]); xn[0][i+1]=xn[0][i]-jacobi*gyou[0]; xn[1][i+1]=xn[1][i]-jacobi*gyou[1]; if(fabs(f(xn[0][i+1],xn[1][i+1]))<ipu && fabs(g(xn[0][i+1],xn[1][i+1]))<ipu)break; } } double f(double x,double y) { double z; z=x*x-y*y; return z; } double g(double x,double y) { double z; z=6*x*y-5; return z; } double gy(double x,double y) { double z; z=6*y; return z; } double fy(double x,double y) { double z; z=-2*y; return z; } double gx(double x,double y) { double z; z=6*x; return z; } double fx(double x,double y) { double z; z=2*x; return z; } void syuturyoku(void) { for(j=0;j<=i;j++){ printf("X%d=%.15lf\n",j,xn[0][j]); printf("y%d=%.15lf\n",j,xn[1][j]); } printf("ε=%.15lf\n",ipu); }

専門家に質問してみよう