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

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

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

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

Bash on Ubuntu on Windows

Bash on Ubuntu on Windowsは、Windows Subsystem for Linux(WSL)の非推奨の名称。Windows10およびWindows Server上でLinuxのバイナリ実行ファイルをネイティブ実行するための互換レイヤーです。

Q&A

解決済

4回答

789閲覧

うまくif文が機能しません。

emilio

総合スコア15

C

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

Bash on Ubuntu on Windows

Bash on Ubuntu on Windowsは、Windows Subsystem for Linux(WSL)の非推奨の名称。Windows10およびWindows Server上でLinuxのバイナリ実行ファイルをネイティブ実行するための互換レイヤーです。

0グッド

0クリップ

投稿2019/12/09 16:08

前提・実現したいこと

参照呼びした変数をif文の中で用いているのですが、上手くいきません。

発生している問題・エラーメッセージ

以下のソースコードを実行すると、 2組の複素数a,bを入力してください。 a=9+9i b=-9-9i a / b = -1.000 +0.000i となってしまいます。 ソースコードは出力が a / b = -1.000 となるように書いているつもりです。

該当のソースコード

ソースコード #include<stdio.h> #include<stdlib.h> #include<math.h> void xy_rt(double x,double y,double *pr,double *r_pt){ *pr =sqrt(x*x+y*y); *r_pt=atan2(y,x); } int division(double x1,double y1, double x2, double y2, double *pre, double *pim){ double r1,r2,t1,t2,r_t1,r_t2; xy_rt(x1,y1,&r1,&r_t1); xy_rt(x2,y2,&r2,&r_t2); *pre=(r1/r2)*cos(r_t1-r_t2); *pim=(r1/r2)*sin(r_t1-r_t2); } typedef struct{ double re, im; } st_complex; int main(){ st_complex a,b,c; printf("2組の複素数a,bを入力してください。\n"); int i; char t1,t2,t3,t4; printf("a="); scanf("%lf%lf%c",&a.re,&a.im,&t1); printf("b="); scanf("%lf%lf%c",&b.re,&b.im,&t2); division(a.re,a.im,b.re,b.im,&c.re,&c.im); __if(c.im!=0 && c.re==0){ printf("a / b = %8.3fi\n",c.im); }else if(c.im==0){ printf("a / b =%8.3f\n",c.re); }else { printf("a / b =%8.3f%+8.3fi\n",c.re,c.im); }____ return 0; }

試したこと

a=9+9i
b=9+9i
a / b = 1.000
この値では上手くいきました。

a=9+9i
b=-9+9i
a / b = 0.000 -1.000i
実数部分が0の場合も上手くいきませんでした。

Windows10 ubuntuを使っています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

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

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

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

guest

回答4

0

すでに回答は出ていますので誤差の話は繰り返しませんが、この際、質問者には実際にどれだけ違いがあるのか、実際に手元で試してみることをお勧めします。こんな関数を作ってみました。

C

1#include <float.h> // DBL_EPSILON 2 3void showDouble(char *name, double d) 4{ 5 union { 6 double dv; 7 unsigned int ui[2]; 8 } v; 9 10 v.dv = d; 11 printf("%10s : 0x%08x.%08x == %10.20g\n", 12 name, v.ui[1], v.ui[0], v.dv); 13} 14 15int main(void) 16{ 17 // 途中省略 18 19 showDouble("c.re", c.re); 20 showDouble("c.im", c.im); 21 showDouble("0.0", 0.0); 22 showDouble("1.0", 1.0); 23 showDouble("-1.0", -1.0); 24 showDouble("EPSILON", DBL_EPSILON); 25 return 0; 26}

doubleは64bitであり、普通unsigned int は32bitなので、ご覧のような共用体変数を使って、doubleの値をビット単位で確認してみよう、同時に浮動小数点としても表示精度を上げて表示してみよう("%10.20g"はテキトーに決めたw)、これを使って計算した値などを表示させてみよう、という事です。
私の手元の実行結果を記します。質問者の手元で同じ結果になるという保証はありません。

sh

1$ ./a.out 22組の複素数a, bを入力してください。 3a = 9+9i 4b = -9-9i 5a / b = -1.000 +0.000i 6 c.re : 0xbff00000.00000000 == -1 7 c.im : 0x3ca1a626.33145c07 == 1.2246467991473532072e-16 8 0.0 : 0x00000000.00000000 == 0 9 1.0 : 0x3ff00000.00000000 == 1 10 -1.0 : 0xbff00000.00000000 == -1 11 EPSILON : 0x3cb00000.00000000 == 2.2204460492503130808e-16 12
  • 0.0 だと思った c.im の値は実は 1.2246... * 10 ^ (-16) という値だった
  • メモリ上では 0x3ca1a626.33145c07 という64bitの値であり 0.0 とは一致しなかった・・・

さらに、例えば、1.0 = 0x3ff00000.00000000 となっている 64bit のビット構成は
浮動小数点 で IEEE754 形式の倍精度浮動小数点形式として説明されています。64bit が符号部・指数部・仮数部の3部分に分かれています。具体的な値で、どのビットがどの部分に当たるか調べてみると面白いですよ。

こういう一段下のレベルを一度体験し確認してみることは案外大事だと私は思っています。

「ほぼ0.0」という値が <float.h> に DBL_EPSILON と定義されているようですね。頻繁に if (x == 0.0) という比較をするのであれば、私なら

#define ISZERO(d) (fabs(d) < DBL_EPSILON)

というマクロを作り if (ISZERO(x)) と書き換えます。ご参考まで。

投稿2019/12/10 03:47

編集2019/12/10 03:52
rubato6809

総合スコア1380

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

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

emilio

2019/12/10 04:28 編集

とても勉強になりました。ありがとうございました! 手元でいくつか試してみたいと思います!
guest

0

ベストアンサー

浮動小数点演算の誤差のせいです。コンピュータのメモリの大きさは有限なので、桁数が大きい数は正確に表せません。特に無理数などは絶対無理です。doubleの場合は、十進数でおよそ15桁ほどの精度しかありません。

a=9+9i

b=9+9i

の場合、aとbは全く同じなので、aの計算で出る誤差と、bの計算で出る誤差は全く同じです。そのため

C

1*pim=(r1/r2)*sin(r_t1-r_t2);

で、r_t1-r_t2の結果は、きっちり0となり、sinの結果も、厳密な0を渡せば、厳密な0を返すので、あとのif(c.im==0)がtrueになります。

しかし、

a=9+9i

b=-9-9i

の場合、r_t1-r_t2の結果は、誤差の出方が違うため、ものすごく小さいが0ではない値になります。あとのif(c.im==0)では、厳密な値で比較するためfalseになってしまいます。

対策としては、0.000が表示されても気にしないか、ごく小さい数は0とみなすかのどちらかでしょう。

投稿2019/12/09 17:07

Bearded-Ockham

総合スコア430

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

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

emilio

2019/12/10 04:16

わかりやすく説明してくださりありがとうございます! 誤差を考慮することで意図したとおりに出力できるようになりました!
guest

0

浮動小数点は実数に対して誤差を含んでいるので等比較はできません。
うまくいったケースはたまたまでしょう。

浮動小数点数の誤差を考慮した比較【double/float型の正しい比較方法】

投稿2019/12/09 16:56

TaroToyotomi

総合スコア1430

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

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

emilio

2019/12/10 04:27

回答ありがとうございます!
guest

0

投稿2019/12/09 16:53

jimbe

総合スコア12632

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

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

emilio

2019/12/10 04:27 編集

回答ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問