アプリ版:「スタンプのみでお礼する」機能のリリースについて

たとえば、以下のコードで、「違う」と表示されるように、浮動小数点の比較に失敗します。

#include <iostream>

int main()
{
float f = 0.1;
if (f == 0.1)
{
std::cout << "同じ";
}
else
{
std::cout << "違う";
}

return 0;
}

double f;
とすれば、同じと表示させるのですが、代入して比較するだけで、比較に失敗するのは、どういう理由なのでしょうか?

A 回答 (4件)

その処理系では「float の 0.1」と「double の 0.1」が違う, ということでしょう.


「0.1」が正確に表現できないことがある, ということは理解できていますか?

この回答への補足

ありがとうございます。

確かに、float と double のサイズは違います(細かく調べていませんが、仮数の桁数もきっと違います)
あと、0.1 は、内部では2進数に展開されるので、無限小数を仮数の桁数で打ち切ることになります。
そうすると、float f = 0.1; と、double f = 0.1; の時で、f の中身は確かに、異なると思います。

それでも、それぞれ、0.1 としての意味のあるデータが格納されていて、これと、0.1 を改めて比較する訳なので、比較は成功するような気がするのですが。

補足日時:2010/11/12 13:34
    • good
    • 0

このURLの解説に詳しく書かれていますのでご一読下さい。


※浮動小数点の誤差の問題です。
http://www.hexadrive.jp/index.php?id=54

この回答への補足

確かに浮動小数点では、2進数展開したときの打ち切り誤差が出てきますので、それを、繰り返したしたり引いたりすると、誤差の蓄積は発生すると思います。

しかし、今回のように、単に代入して、同じ数値で比較しただけで、比較に失敗するのは不思議な気がするのですが。

補足日時:2010/11/12 13:36
    • good
    • 0

「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 同士の比較ですので、等しいという結果になります。
    • good
    • 0
この回答へのお礼

ありがとうございました。

0.1 というリテラルそのものが、double の型を持っているとは気づきませんでした。
なんとなく、 f == 0.1 という比較で、f の型に合わせて 0.1 を変換して、比較してくれるような気がしていました。

> なお、比較を「f==0.1f」にすれば、float 同士の比較ですので、等しいという結果になります。
とのことで、そう言われて改めて、確認したら、f というサフィックスが確かにあります。
そういうわけだったのですね。
(実際に確認したら、確かに、「同じ」という結果になりました)

よくわかりました。

お礼日時:2010/11/12 14:16

横から失礼します。


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)
と書くと等しくなるんですが、ご理解の手がかりになれば幸いです。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!