質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

1580閲覧

sinx+x=1の計算をしたい

Mr_K

総合スコア28

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/04/17 05:31

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mather

2019/04/17 05:45

「うまくいきません」という部分を具体的に「期待したことは何で、実際に起っていることは何で、試したことは何か」書いてください。 おそらく解が表示されないのだと思いますが…。
mather

2019/04/17 05:47

なお、学校の課題に関することはまず担当教官や同じ授業を受けている人に質問をするようにしましょう。
guest

回答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 が以下の点で問題

  1. 0.000001 ずつ +x 方向に移動して f(x) の値を確認するというやり方なので、完全に0になる点が見つかるとは限らない。
  2. 浮動小数点数同士の演算では、丸め誤差が発生するので、等号を使った比較は意図した通りには動かない。十分近いかどうかで判断する必要がある。

浮動小数点数の誤差を考慮した比較【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
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

.sin(x) + x = 1のような非線形方程式の数値解法には

  1. 二分法
  2. Newton法
  3. 割線法
  4. はさみうち法

などがあります。今回ははさみうち法で求めたいと思います。

Qiita 非線形方程式の数値解法

はさみうち法の特徴として

  1. 微分係数を求める必要がない
  2. 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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2019/04/17 09:36 編集

"ニュートン"だろが"はさみうち"だろが、(強い)単純増加/減少関数じゃないと求まらんことがあるので注意。
guest

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

fana

総合スコア11652

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2019/04/18 02:51

おっと,最後は sin(BestX) だけでなく, 1-BestX も表示すべきですね.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問