web-dev-qa-db-ja.com

浮動小数点の比較

int main()
{
    float a = 0.7;
    float b = 0.5;
    if (a < 0.7)
    {
       if (b < 0.5) printf("2 are right");
       else         printf("1 is right");
    }
    else printf("0 are right");
}

このコードの出力は0 are right。しかし、残念なことに、出力は1 is right なぜ?

64
sasidhar
int main()
{
    float a = 0.7, b = 0.5; // These are FLOATS
    if(a < .7)              // This is a DOUBLE
    {
      if(b < .5)            // This is a DOUBLE
        printf("2 are right");
      else
        printf("1 is right");
    }
    else
      printf("0 are right");
}

フロートは比較中に倍精度に昇格されます。浮動小数点は倍精度よりも精度が低いため、浮動小数点は0.7なのでnotは0.7と同じです。この場合、フロートとしての0.7は、昇格時にダブルとしての0.7より劣ります。クリスチャンが言ったように、2の累乗である0.5は常に正確に表されるため、テストは期待どおりに機能します。0.5 < 0.5はfalseです。

だからどちらか:

  • floatdoubleに変更する、または:
  • .7.5.7f.5fに変更します。

期待どおりの動作が得られます。

130
user703016

問題は、比較している定数がdoubleではなくfloatであることです。また、定数を5の係数などの簡単に表現できるものに変更すると、0 is rightになります。例えば、

main()
{
    float a=0.25,b=0.5; 
    if(a<.25) 
       {
       if(b<.5) 
               printf("2 are right");
       else
               printf("1 is right");
       }
else
printf("0 are right");
}

出力:

0 are right

このSOに関する質問floatとdoubleの比較に最も効果的な方法はこのトピックをカバーしています。

また、cygnusの 浮動小数点数の比較 に関するこの記事では、いくつかのヒントを示しています。

IEEEの浮動小数点形式と倍精度形式は、数値が「辞書式順序付け」されるように設計されています。これは、IEEEアーキテクトのWilliam Kahanの言葉では、「同じ形式の2つの浮動小数点数が順序付けられている場合(たとえば、x <y)、これらのビットは、Sign-Magnitude整数として再解釈される場合と同じ方法で順序付けされます。」

つまり、メモリ内の2つの浮動小数点数を取得し、それらのビットパターンを整数として解釈して比較すると、浮動小数点比較を行わなくても、どちらが大きいかがわかります。 C/C++言語では、この比較は次のようになります。

if (*(int*)&f1 < *(int*)&f2)

この魅力的な構文は、f1のアドレスを取得して整数ポインターとして扱い、逆参照することを意味します。これらのポインタ操作はすべて高価に見えますが、基本的にはすべてキャンセルされ、単に「f1を整数として扱う」ことを意味します。同じ構文をf2に適用するため、行全体は「f1とf2を比較し、浮動小数点数ではなく整数として解釈されるメモリ内表現を使用する」ことを意味します。

15
user195488

Floatからdoubleに変換する際の丸めの問題が原因です

3
Win32.Neshto

一般に、等価とフロートを比較することは危険なビジネスです(これは、>の境界で比較しているため、実際に行っていることです)。バイナリについて言えます

0.5= 0.1、floatまたはdoubleで同じになります。

0.7=0.10110011001100 etc永遠に、0.7はバイナリで正確に表すことができず、丸めエラーが発生し、floatとdoubleの間で(非常にわずかに)異なる場合があります

Floatとdoubleの間を移動すると、小数点以下の桁数が異なるため、一貫性のない結果になることに注意してください。

2
Richard Tingle

また、ところで、あなたはあなたの論理にエラーがあります0は正しいです。出力0が正しい場合は、bをチェックしません。しかし、あなたが本当に成し遂げようとしていることは、全体的に少し不思議です。浮動小数点数と倍精度浮動小数点数の間の浮動小数点比較には、分単位の変動があるため、状況に応じてデルタ「許容範囲」の変動と比較する必要があります。私は常に、作業を実行するだけのインライン関数を使用してこれを行ってきました(マクロで1回実行しましたが、面倒すぎます)。とにかく、そうですね、このタイプの例では丸めの問題がたくさんあります。浮動小数点のものを読んで、.7が.7fとは異なり、.7を浮動小数点数に割り当てると、倍精度浮動小数点数にキャストされ、値の正確な性質が変更されます。しかし、あなたが私に向けられたものをチェックしたのでbが間違っているというプログラミングの仮定、そして私はそれに注意しなければなりませんでした:)

0
Jay Kramer