c言語でsinx+x=1の計算をするという課題が出たのですが、上手くいきません。以下がコードになっています。わかる方いらっしゃいましたらお答えください。
#include <stdio.h> #include <math.h> #include <float.h> #pragma warning(disable: 4819) int i; double x = 0; double ya = 0, yb = 0; double main(void) { for (i=0; i < 1000000000; i++) { x += 0.000001; ya = sin(x); yb = 1-x; printf("%f, %f\n", ya, yb); if (ya == yb) { printf("解は%fです", x); printf("その時のyは%fです", ya); break; } } return 0; }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/04/17 05:47
回答3件
0
sin(x) + x = 1 ⇔ xin(x) + x - 1 = 0 をニュートン法とかで解けばいいと思います。
理論的なしくみはニュートン法で調べれば解説記事がいくらでもでてくるので、そちらを参照ください。
ニュートン法とは何か??ニュートン法で解く方程式の近似解 - Qiita
c
1#include <math.h> 2#include <stdio.h> 3 4#define EPS 0.0000001 5#define ITERATIONS 100 6 7double f(double x) 8{ 9 return sin(x) + x - 1; 10} 11 12double df(double x) 13{ 14 return cos(x) + 1; 15} 16 17int main(void) 18{ 19 int k; 20 double x_new; 21 double x = 0; // 初期点 22 printf("x0: %f", x); 23 24 for (k = 0; k < ITERATIONS; ++k) { 25 x_new = x - f(x) / df(x); // 更新 26 printf("%d: x=%f, x_new=%f\n", k, x, x_new); 27 28 if (fabs(x - x_new) < fabs(x) * EPS) 29 break; 30 x = x_new; 31 } 32 33 if (k == ITERATIONS) 34 printf("no solution\n"); 35 else 36 printf("solution: x=%f\n", x); 37} 38
x0: 0.0000000: x=0.000000, x_new=0.500000 1: x=0.500000, x_new=0.510958 2: x=0.510958, x_new=0.510973 3: x=0.510973, x_new=0.510973 solution: x=0.510973
追記
元のコードの ya == yb
が以下の点で問題
- 0.000001 ずつ +x 方向に移動して f(x) の値を確認するというやり方なので、完全に0になる点が見つかるとは限らない。
- 浮動小数点数同士の演算では、丸め誤差が発生するので、等号を使った比較は意図した通りには動かない。十分近いかどうかで判断する必要がある。
浮動小数点数の誤差を考慮した比較【double/float型の正しい比較方法】 | MaryCore
c
1#include <math.h> 2#include <stdio.h> 3 4#define EPS 0.00001 5#define ITERATIONS 1000000000 6 7int main() 8{ 9 double x = 0; 10 for (int i = 0; i < ITERATIONS; ++i) { 11 double y = sin(x) + x - 1; 12 13 if (fabs(y) < EPS) { 14 printf("solution: f(%f) = %f\n", x, y); 15 // solution: f(0.510969) = -0.000008 16 break; 17 } 18 19 x += 0.000001; // 移動 20 } 21 return 0; 22} 23
投稿2019/04/17 05:43
編集2019/04/17 05:59総合スコア21956
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
.sin(x) + x = 1
のような非線形方程式の数値解法には
- 二分法
- Newton法
- 割線法
- はさみうち法
などがあります。今回ははさみうち法で求めたいと思います。
はさみうち法の特徴として
- 微分係数を求める必要がない
- Newton法の初期値を求めるのに適している
があります。
c
1#include <stdio.h> 2#include <math.h> 3 4double f(double); 5double calc(double, double); 6 7int main(void){ 8 double alpha; 9 alpha = calc(0,M_PI / 6.0); 10 printf("%f \n", alpha); 11 return 0; 12} 13 14double f(double x){ 15 return sin(x) + x - 1; 16} 17 18double calc(double a, double b){ 19 double c; 20 do{ 21 c = ( a * f(b) - b * f(a) ) / ( f(b) - f(a) ); 22 if(f(c) == 0){ 23 break; 24 } 25 else if( f(a) * f(c) < 0){ 26 b = c; 27 } 28 else if( f(a) * f(c) > 0){ 29 a = c; 30 } 31 }while(fabs(f(c)) > 1e-10); 32 33 return c; 34} 35 36
結果 x = 0.510973
はさみうち法の特徴で「Newton法の初期値を求めるのに適している」があるので求めた解を利用して
ニュートン法で求めてみました。
c
1#include <stdio.h> 2#include <math.h> 3 4double df(double); 5double f(double); 6double calc(double, double); 7double newton(double); 8 9int main(void){ 10 double alpha,alpha2; 11 alpha = calc(0,M_PI / 6.0); 12 alpha2 = newton(0); 13 printf("はさみうち法 : %.20f \n", alpha); 14 printf("ニュートン法 : %.20f \n", alpha2); 15 return 0; 16} 17 18double f(double x){ 19 return sin(x) + x - 1; 20} 21double df(double x){ 22 return cos(x) + 1; 23} 24 25double calc(double a, double b){ 26 double c; 27 do{ 28 c = ( a * f(b) - b * f(a) ) / ( f(b) - f(a) ); 29 if(f(c) == 0){ 30 break; 31 } 32 else if( f(a) * f(c) < 0){ 33 b = c; 34 } 35 else if( f(a) * f(c) > 0){ 36 a = c; 37 } 38 }while(fabs(f(c)) > 1e-10); 39 40 return c; 41} 42 43double newton(double x){ 44 double new_x; 45 while(1){ 46 new_x = x - f(x) / df(x); 47 if(fabs( f(x) ) / df(x) < 1e-10){ 48 break; 49 } 50 if(fabs( f(x) ) < 1e-10){ 51 break; 52 } 53 x = new_x; 54 } 55 return new_x; 56} 57 58 59
結果
はさみうち法 : 0.51097342939223233670 ニュートン法 : 0.51097342938856915580
投稿2019/04/17 08:22
退会済みユーザー
総合スコア0
0
ベストアンサー
「他の探索法でやれ」というのも回答でしょうけど,
とりあえず質問者様が行っている方法に近い処理方法も欲しいのではないかな,ということで,
【xを0から0.000001刻みで調べて行って「一番良いx」を答えにする】というものを.
こんな感じでしょうか.
int main(void) { double BestX = 0; //一番良かったxの値を記録 double BestAbsDiff = DBL_MAX; //一番良かった際の | sin(x) - (1-x) | の値を記録 double x = 0; while( 1 ) { double ya = sin( x ); double yb = 1.0 - x; double Diff = ya - yb; double AbsDiff = fabs( Diff ); if( AbsDiff < BestAbsDiff ) {//これまでよりも良いなら結果を更新 BestX = x; BestAbsDiff = AbsDiff; } if( Diff >= 0.0 )break; //(※)終了条件 x += 0.000001; } printf( "解は%fです\n", BestX ); printf( "その時のyは%fです\n", sin(BestX) ); return 0; }
(※)終了条件 に関しては
- y = sin(x)
- y = 1-x
の2本のグラフを描いて眺めてみれば,
xを0から増加させていくなら,sin(x)が1-xを上回ったら時点でもうこれ以上探さなくてよいことがわかるので,このようにしています.
(問題で扱う式自体が特定のものに指定されているなら,そういう知見(?)を実装しても良いかな,と)
投稿2019/04/18 02:48
総合スコア11652
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。