• ベストアンサー

浮動小数点の比較について

たとえば、以下のコードで、「違う」と表示されるように、浮動小数点の比較に失敗します。 #include <iostream> int main() { float f = 0.1; if (f == 0.1) { std::cout << "同じ"; } else { std::cout << "違う"; } return 0; } double f; とすれば、同じと表示させるのですが、代入して比較するだけで、比較に失敗するのは、どういう理由なのでしょうか?

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

  • ベストアンサー
  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.3

「0.1」というリテラルはdouble型になります。 そして、float と double の値を比較するときは、float 値がdouble に変換されてから、double同士の比較として処理されます。 つまり、「f==0.1」は、 「0.1 をfloatで表現したものをdoubleに変換したもの」と「0.1をdoubleで表現したもの」の比較を行います。 そのため、float の精度の低さから、等しくないという結果になります。 参考:IEEE754(一般的な浮動小数点数)表現だと、 float : 指数部8bit/仮数部24bit (float)0.1 = 1.10011001100110011001101b ×2^-4 double : 指数部11bit/仮数部53bit (double)0.1 = 1.1001100110011001100110011001100110011001100110011010b ×2^-4 ですので、「f==0.1」という比較の場合、(float)0.1 はdouble に変換され、 1.10011001100110011001101 00000000000000000000000000000×2^-4 1.10011001100110011001100 11001100110011001100110011010×2^-4 の比較になります。 なお、比較を「f==0.1f」にすれば、float 同士の比較ですので、等しいという結果になります。

yumeno_kira
質問者

お礼

ありがとうございました。 0.1 というリテラルそのものが、double の型を持っているとは気づきませんでした。 なんとなく、 f == 0.1 という比較で、f の型に合わせて 0.1 を変換して、比較してくれるような気がしていました。 > なお、比較を「f==0.1f」にすれば、float 同士の比較ですので、等しいという結果になります。 とのことで、そう言われて改めて、確認したら、f というサフィックスが確かにあります。 そういうわけだったのですね。 (実際に確認したら、確かに、「同じ」という結果になりました) よくわかりました。

その他の回答 (3)

  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.4

横から失礼します。 floatとdoubleの0.1が同じ値でないことは、#2様のご指摘から明らかかと思います。 質問者様のソースでは、最初に「float f = 0.1;」でdouble型の0.1をfloatに 切り詰めているのですが、そこはご理解しておられるでしょうか? ソース中の「if (f == 0.1)」は、実際には「if ((double)f == 0.1)」 とfが拡張されます。 一度切り詰めたfがここで拡張されるのですから、一部情報が欠損し double表現時の0.1とは異なる値になるため、等しくありません。 例えば if (f == 0.1f) と書くと等しくなるんですが、ご理解の手がかりになれば幸いです。

  • YUI_AI
  • ベストアンサー率45% (303/661)
回答No.2

このURLの解説に詳しく書かれていますのでご一読下さい。 ※浮動小数点の誤差の問題です。 http://www.hexadrive.jp/index.php?id=54

yumeno_kira
質問者

補足

確かに浮動小数点では、2進数展開したときの打ち切り誤差が出てきますので、それを、繰り返したしたり引いたりすると、誤差の蓄積は発生すると思います。 しかし、今回のように、単に代入して、同じ数値で比較しただけで、比較に失敗するのは不思議な気がするのですが。

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

その処理系では「float の 0.1」と「double の 0.1」が違う, ということでしょう. 「0.1」が正確に表現できないことがある, ということは理解できていますか?

yumeno_kira
質問者

補足

ありがとうございます。 確かに、float と double のサイズは違います(細かく調べていませんが、仮数の桁数もきっと違います) あと、0.1 は、内部では2進数に展開されるので、無限小数を仮数の桁数で打ち切ることになります。 そうすると、float f = 0.1; と、double f = 0.1; の時で、f の中身は確かに、異なると思います。 それでも、それぞれ、0.1 としての意味のあるデータが格納されていて、これと、0.1 を改めて比較する訳なので、比較は成功するような気がするのですが。

関連するQ&A

  • 浮動小数点表現

    浮動小数点表現の問題で以下の実行結果を元にfloat型変数 f に与えた実数の実際に格納されているビット列を表示するプログラムを作りたいのですが、 #include<stdio.h> main() { float a; scanf("%f",&a); printf("%f",a); } この程度までしか作れません。ポインタを使ってアドレスを表示することは分るのですが…。 どなたか教えていただけると助かります。 実行結果 Size of Float : 4 byte Size of Int : 4 byte f=0.500000000000000 00111111000000000000000000000000

  • 浮動小数点エラー

    #include<stdio.h> main (){ float D[5][6] = { {0,0,151.9058382,111.8925551,238.1626765,145.6362657},   {0,151.9058382,0,256.9532465,317.3522119,232.5861795}, {0,111.8925551,256.9532465,0,181.0294098,114.6471}, {0,238.1626765,317.3522119,181.0294098,0,93.41311845} ,   {0,145.6362657,232.5861795,114.6471,93.41311845,0}, };   float data[100][100] ; int n=5; float sum; int i,l; for(i=1;i<=n-2;i++) { sum=0; for(l=i+2;l<=n;l++) { sum=sum+D[i][l]; } ◎ data[i]=D[i][i+1]/(sum/(n-(D+1)));  ←この行 } for (i=1;i<=n;i++){ printf("%f",data[i]); } return (0); } 上のプログラムで、◎の行に浮動小数点の不正な使用とエラーがでてしまいます。 参考書、ヘルプで調べたもののなぜエラーとなるか分かりませんでした。 解決できますでしょうか?

  • C#のキャストについて(32bit浮動小数点)

    こんにちは。 現在、Visual Studio 2005を使用してC#のプログラムを作成しています。 32bitの浮動小数点のデータを表示しようとしているのですがうまくいきません。 具体的な例としては 0x42F6E9E0  → 123.456789 0x4476E9E0  → 987.654321 のように変換した結果を表したいと考えています。 c言語では int main() { int h = 0x42F6E9D5; float f; f = *(float *)(&h); return 0; } のようにすればfで値(123.45678)が取得できたのですが、 これと同じ事をC#ではどのように書くのでしょうか? ポインタを含んだキャストのやり方がわかりません。 以上よろしくお願い致します。

  • ''C++の条件分岐分からないんですが

    #include<iostream> using namespace std; int main(){ int a; cout << "数値を入力してください\n"; cin >> a; if( a > 30) cout <<"31以上ですね\n"; } else if(a<10){ cout <<"10未満ですね\n"; } else { cout <<"30以下で10以上ですね\n"; } return 0; } これが例文なんですが、 変数aの値がbより小さい場合には、『aはbより小さいです』と表示させ、大きい場合には"a=a+b"を計算させる 文字変数mの中身が'a'ならば、『aが格納されています』と表示させて、'a'でないならば『'a'でない文字が格納されています』と表示させたあと、変数bとcを使った『b=b+c』を計算する。 変数aが、変数bより小さい場合には、『aはbより小さいです』と表示し、変数bより大きい場合には、『aはbより大きいです』と表示し、変数bと等しい場合には、『aとbは等しいです』と表示する #include<iostream> using namespace std; int main(){ int a; if(a < b) { __cout("aはbより小さいです\n"); } else { __c = a + b; }return 0; } #include<iostream> using namespace std; int main(){ int a; if(m == 'a') __cout("aが格納されています\n"); } else { __cout("\'a\'でない文字が格納されています\n"); } return 0; } #include<iostream> using namespace std; int main(){ int a; if(a < b) { __cout("aはbより小さいです\n"); } else if(a == b) { __cout("aとbは等しいです\n"); } else { __cout("aはbより大きいです\n"); } return 0; } これ合ってますか?あとプログラミング環境すらないので実行結果教えてもらっていいですか?

  • 6行ソースをコンパイル可能にしてください

    std::fflush(stdout); という所が間違っているんだと思いますが#include <iostream>は#include <iostream.h>にせずにコンパイルしたいです。 #include <iostream> int main(){ std::cout << "h\n"; std::fflush(stdout); return 0; }

  • isdigitの挙動について

    #include <iostream> #include <ctype.h> using namespace std; int main() { int i = 100; if (isdigit(i)){ cout << "true"; }else{ cout << "false"; } return 0; } というプログラムを実行したのですが、falseが標準出力に表示されます。 i=100なので、isdigitでtrueが返ってくるのだと思っていたのですが、なぜfalseが帰ってくるのでしょうか?? どなたか詳しい方いらっしゃったらご教示いただけると幸いです。

  • 【C++】関数ポインタの使い方

    関数ポインタの使い方で悩んでいます。 下記の (1)のようにグローバルメソッドとして定義したメソッドを関数ポインタに代入することは出来るのですが、 (2)のようにクラスのメンバメソッドとして定義したメソッドは関数ポインタに代入することは出来ませんでした。 Error:バインドされた関数へのポインターは関数の呼び出しにのみ使用できます。 というエラーが発生します。 関数ポインタに外部参照でメソッドを代入することは出来ないのでしょうか? -----(1)------------------------------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; int f(int a, int b){ return a * b; } int _tmain(int argc, _TCHAR* argv[]) { typedef int (* FUNC_POINTER)(int, int); FUNC_POINTER fp; fp = f; cout << fp(1,2) <<endl; getchar(); return 0; } ------------------------------------------------------------------------- -----(2)------------------------------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; class MPointerList{ public: int f(int a, int b){ return a * b; } }; int _tmain(int argc, _TCHAR* argv[]) { typedef int (* FUNC_POINTER)(int, int); FUNC_POINTER fp; //fp = f; MPointerList mP; fp = mP.f; cout << fp(1,2) <<endl; getchar(); return 0; } -------------------------------------------------------------------------

  • C++の配列について

    #include <iostream> using namespace std; int main() { float w[] = {1.2,2.3,3.4,4.5,5.6}; float x[] = {4.8,2.6,1.3,9.1,8.7}; float u = 0.0; int i; for(i=0;i<5;i=i++) { u += w[i] * x[i]; } cout << "u=" << u << "です\n"; return 0; } u=105.83って出たんですが、これは何をしているプログラムなんですか

  • 警告「代入される前に使われている」を出す方法

    bccで以下のコードをコンパイルすると。 「'i' は、おそらく値が代入される前に使われている」 と警告が出ますが、 「'h' は、おそらく値が代入される前に使われている」 とは警告を出してくれません。 警告を出す方法ってないでしょうか? Hogeメンバに bool 型の初期化フラグでも実装しようかな・・・。 #include <iostream> class Hoge { public: Hoge(){ } Hoge( int i ){ t = i; } operator int(){ return t; } int t; }; int main() { int i; Hoge h; std::cout << i << std::endl; std::cout << h << std::endl; return 0; }

  • 添字演算子

    #include <iostream> class hoge{ private: int a; public: hoge(){ a = 0; } int operator+(int fuga){ a = a + fuga; return a; } int operator[](int fuga){ return 1; } }; int main(){ hoge* p; p = new hoge; std::cout << ((*p) + 5) << std::endl; std::cout << ((*p)[1] ) << std::endl; // 5 // 1 // std::cout << ((*p) [] 1); エラーです。何故ですか? }

専門家に質問してみよう