質問

float f = 0.7;
if( f == 0.7 )
    printf("equal");
else
    printf("not equal");

なぜ出力が not equal ?

なぜこのようなことが起こるのでしょうか?

役に立ちましたか?

解決

なぜなら、あなたの文の

これは起こります

  if(f == 0.7)

0.7をdoubleとして扱われます。値がfloatとして扱われていることを確認するために0.7fを試します:

  if(f == 0.7f)

しかし、マイケルはあなたの以下のコメントで提案されているように、浮動小数点値の正確な等価性をテストすることはありません。

他のヒント

既存のものを補完する

この答:0.7はfloatとして(またはdoubleとして)のいずれか正確に表現されていないことに注意してください。それが正確に表現された場合は、そこに戻って、二重に、その後フロートとする変換情報の損失もないだろう、とあなたはこの問題を持っていないでしょう。

それも、標準の丸めが持っているモードで実行時に行われるかどうかについてはとてもあいまいである場合は特に、正確に表現できない浮動小数点リテラル定数のコンパイラの警告がなければならないと主張することができ別の丸めモードと時間として、またはコンパイル時に設定されます。

正確に表現することができます。

すべての非整数の数字は、彼らの最後の小数点以下の桁として5てきました。残念ながら、その逆は真ではありません。いくつかの数字は、彼らの最後の小数点以下の桁として5しており、正確に表現することはできません。小さな整数はすべて正確に表現することができ、かつ2の累乗による除算は、限り、あなたは非正規化数のレルムを入力しないと、表現することができる他に表現することができる番号を変換します。

まず、float 数値の内部を見てみましょう。0.1f は 4 バイト長 (binary32) で、16 進数では次のようになります。
3D CC CC CD.
標準の IEEE 754 で 10 進数に変換するには、次のようにする必要があります。

enter image description here
バイナリ 3D CC CC CD では、
0 01111011 1001100 11001100 11001101
ここで、最初の桁は符号ビットです。0 は (-1)^0 という数値が正であることを意味します。
2 番目の 8 ビットは指数です。2 進数では 01111011、10 進数では 123 です。しかし、実際の指数は 123-127(常に 127)=-4, 、これは、取得する数値に 2^(-4) を掛ける必要があることを意味します。
最後の 23 バイトは有効桁数の精度です。最初のビットには 1/(2^1) (0.5) を掛け、2 番目のビットには 1/(2^2) (0.25) を掛けます。ここで得られるものは次のとおりです。


enter image description here enter image description here

すべての数値 (2 の累乗) を加算し、それに 1 を加算する必要があります (標準では常に 1)。それは
1,60000002384185791015625
次に、この数値に 2^(-4) を掛けてみましょう。これは指数からのものです。上記の数値を 2 で 4 回割るだけです。
0,100000001490116119384765625
MS電卓を使ってみた


**

さて、第二部です。10 進数から 2 進数への変換。

**
私は 0.1 という数字をとります
整数部分がないので楽です。最初の符号ビット - それは 0 です。指数と仮数の精度をこれから計算します。ロジックは 2 の整数 (0.1*2=0.2) を掛け、それが 1 より大きい場合は減算して続行します。
enter image description here
数値は .00011001100110011001100110011 です。standart では、1.(何か) を取得する前に左にシフトする必要があると言います。この数字から計算すると、4 つのシフトが必要であることがわかります。 指数(127-4=123)。そして、仮数部の精度は次のようになります。
10011001100110011001100(そして失われたビットがあります)。
今度は整数です。符号ビット 0 指数は 123 (01111011)、仮数精度は 10011001100110011001100 そしてそれは全体です
00111101110011001100110011001100 前の章のものと比較してみましょう
00111101110011001100110011001101
ご覧のとおり、最後のビットは等しくありません。数字を切り捨てているからです。CPU とコンパイラは、 が有効桁数の精度を保持できないことを認識し、最後のビットを 1 に設定するだけです。

あなたが直面している問題は、他のコメント投稿者が指摘しているように、初期化エラーや計算の丸め誤差により、 == 演算子が false を返す原因となる小さな違いが生じる可能性があるため、float 間の正確な等価性をテストするのは一般的に安全ではないということです。

より良い実践は、次のようなことを行うことです

float f = 0.7;
if( fabs(f - 0.7) < FLT_EPSILON )
    printf("equal");
else
    printf("not equal");

FLT_EPSILON がプラットフォームに適した小さな浮動小数点値として定義されていると仮定します。

丸め誤差や初期化誤差が FLT_EPSILON の値を超える可能性は低いため、これにより、探している信頼性の高い等価性テストが得られます。

ウェブ周りの答えの多くは、これは特殊な場合のみ有効です浮動小数点数の間abosulute違いを見てのミスを犯す、堅牢な方法は、以下のように相対的な差を見ることである。

      // Floating point comparison:

        bool CheckFP32Equal(float referenceValue, float value)
        {
           const float fp32_epsilon = float(1E-7);
           float abs_diff = std::abs(referenceValue - value);

           // Both identical zero is a special case
           if( referenceValue==0.0f && value == 0.0f)
              return true;

           float rel_diff = abs_diff / std::max(std::abs(referenceValue) , std::abs(value) ); 

           if(rel_diff < fp32_epsilon)
                 return true;
           else 
                 return false;

        }

もう一つの近くに正確な質問は、このように、この1年の後半の答えにリンクされました。私は上記の回答が完了していると思ういけない。

int fun1 ( void )
{
      float x=0.7;
      if(x==0.7) return(1);
      else       return(0);
}
int fun2 ( void )
{
      float x=1.1;
      if(x==1.1) return(1);
      else       return(0);
}
int fun3 ( void )
{
      float x=1.0;
      if(x==1.0) return(1);
      else       return(0);
}
int fun4 ( void )
{
      float x=0.0;
      if(x==0.0) return(1);
      else       return(0);
}
int fun5 ( void )
{
      float x=0.7;
      if(x==0.7f) return(1);
      else       return(0);
}
float fun10 ( void )
{
    return(0.7);
}
double fun11 ( void )
{
    return(0.7);
}
float fun12 ( void )
{
    return(1.0);
}
double fun13 ( void )
{
    return(1.0);
}

Disassembly of section .text:

00000000 <fun1>:
   0:   e3a00000    mov r0, #0
   4:   e12fff1e    bx  lr

00000008 <fun2>:
   8:   e3a00000    mov r0, #0
   c:   e12fff1e    bx  lr

00000010 <fun3>:
  10:   e3a00001    mov r0, #1
  14:   e12fff1e    bx  lr

00000018 <fun4>:
  18:   e3a00001    mov r0, #1
  1c:   e12fff1e    bx  lr

00000020 <fun5>:
  20:   e3a00001    mov r0, #1
  24:   e12fff1e    bx  lr

00000028 <fun10>:
  28:   e59f0000    ldr r0, [pc]    ; 30 <fun10+0x8>
  2c:   e12fff1e    bx  lr
  30:   3f333333    svccc   0x00333333

00000034 <fun11>:
  34:   e28f1004    add r1, pc, #4
  38:   e8910003    ldm r1, {r0, r1}
  3c:   e12fff1e    bx  lr
  40:   66666666    strbtvs r6, [r6], -r6, ror #12
  44:   3fe66666    svccc   0x00e66666

00000048 <fun12>:
  48:   e3a005fe    mov r0, #1065353216 ; 0x3f800000
  4c:   e12fff1e    bx  lr

00000050 <fun13>:
  50:   e3a00000    mov r0, #0
  54:   e59f1000    ldr r1, [pc]    ; 5c <fun13+0xc>
  58:   e12fff1e    bx  lr
  5c:   3ff00000    svccc   0x00f00000  ; IMB

なぜfun3と1とではない他人を返すfun4たのですか?なぜfun5に動作しますか?

これは、言語についてです。言語は、あなたはそれが単一で、この構文0.7fを使用しない限り、0.7倍であることを述べています。だから、

  float x=0.7;

二重0.7は、単一に変換され、Xに格納されます。

  if(x==0.7) return(1);

言語は、我々はxの単一の二重0.7と比較して二重に変換されるように高精度に推進しなければならないと言います。

00000028 <fun10>:
  28:   e59f0000    ldr r0, [pc]    ; 30 <fun10+0x8>
  2c:   e12fff1e    bx  lr
  30:   3f333333    svccc   0x00333333

00000034 <fun11>:
  34:   e28f1004    add r1, pc, #4
  38:   e8910003    ldm r1, {r0, r1}
  3c:   e12fff1e    bx  lr
  40:   66666666    strbtvs r6, [r6], -r6, ror #12
  44:   3fe66666    svccc   0x00e66666

シングル3f333333 ダブル3fe6666666666666

その答えは、IEEE 754のままである場合アレクサンドルが指摘したように、

単一の

であります
  

seeeeeeeefffffffffffffffffffffff

とダブルです。

  

seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff

52小数のビットではなく持つ単一23を有する。

00111111001100110011... single
001111111110011001100110... double

0 01111110 01100110011... single
0 01111111110 01100110011... double

ベース10内と同じように1 /第三は、永遠に... 0.3333333です。ここでは繰り返しパターン0110

を持っています
01100110011001100110011 single, 23 bits
01100110011001100110011001100110.... double 52 bits.

そして、ここで答えです。

  if(x==0.7) return(1);
それが戻って変換されるとき、

xは、その端数として01100110011001100110011が含まれています 分数を倍にすることです。

01100110011001100110011000000000....

に等しくありません
01100110011001100110011001100110...

が、ここで

  if(x==0.7f) return(1);

プロモーションdoesntのは、同一のビットパターンが互いに比較されることが起こる。

なぜ1.0動作しますか?

00000048 <fun12>:
  48:   e3a005fe    mov r0, #1065353216 ; 0x3f800000
  4c:   e12fff1e    bx  lr

00000050 <fun13>:
  50:   e3a00000    mov r0, #0
  54:   e59f1000    ldr r1, [pc]    ; 5c <fun13+0xc>
  58:   e12fff1e    bx  lr
  5c:   3ff00000    svccc   0x00f00000  ; IMB

0011111110000000...
0011111111110000000...

0 01111111 0000000...
0 01111111111 0000000...

両方の場合において、画分はすべてゼロです。だから、精度の損失がない倍増するダブルからシングルへの変換。それは正確に2つの値の作品のビット比較を倍増する単一から変換します。

halfdanによって最高の投票と確認答えが正解である

、これは、混合精度の場合であり、あなたは比較に等しいやるべきではありません。

その答えに示す理由波平。 0.7は1.0作品を失敗しました。なぜ0.7は波平が示さ失敗しました。重複した質問1.1も同様に失敗します。

<時間>

EDIT

等号がここでの問題から取り出すことができ、それはすでに回答されている別の質問ですが、それは同じ問題であり、また「何を...」最初のショックを持っています。

int fun1 ( void )
{
      float x=0.7;
      if(x<0.7) return(1);
      else       return(0);
}
int fun2 ( void )
{
      float x=0.6;
      if(x<0.6) return(1);
      else       return(0);
}

Disassembly of section .text:

00000000 <fun1>:
   0:   e3a00001    mov r0, #1
   4:   e12fff1e    bx  lr

00000008 <fun2>:
   8:   e3a00000    mov r0, #0
   c:   e12fff1e    bx  lr

なぜ1番組以上未満、その他などしていますか?彼らは等しいはずであるときます。

上記のことから、我々は0.7の話を知っています。

01100110011001100110011 single, 23 bits
01100110011001100110011001100110.... double 52 bits.

01100110011001100110011000000000....

より少ないます。

01100110011001100110011001100110...

は0.6は、異なる繰り返しパターン0011でなく0110

が、単一にまたは一般的に二重に換算すると表すと シングルIEEE 754のように

00110011001100110011001100110011.... double 52 bits.
00110011001100110011001 is NOT the fraction for single
00110011001100110011010 IS the fraction for single

IEEE 754は、丸めモードを使用して切り上げ、ゼロまたはラウンドを切り捨てます。コンパイラは、デフォルトで切り上げ傾向にあります。あなたは小学校12345678に丸め覚えていれば、私は上から3桁目を四捨五入したい場合は数字が後に5以上が、その後切り上げされている場合には、次の桁1235000から12300000が、丸いだろう。 5バイナリ1にベース(10進数)10の1/2である私たちは四捨五入したい位置の後の数字は1が、その後、他のdontを切り上げているので、もしベースの1/2です。だから、0.7のために、私たちは0.6のために、我々は切り上げるか、切り上げいませんでします。

そして今、

ことを確認することは容易です
00110011001100110011010

ための二重に変換(X <0.7)

00110011001100110011010000000000....

タグよりも大きく、
00110011001100110011001100110011....

を使用しての話をしなくても、問題はまだ自分自身0.7提示等しいことは、二重0.7fであるため、単一であるそれらが異なる場合は、操作は最高の精度に昇格されます。

このことを考慮:

int main()
{
    float a = 0.7;
    if(0.7 > a)
        printf("Hi\n");
    else
        printf("Hello\n");
    return 0;
}

もし (0.7 > a) ここで a は float 変数であり、 0.7 は二重定数です。二重定数 0.7 は浮動小数点変数 a より大きいです。したがって、if 条件が満たされ、出力されます。 'Hi'

例:

int main()
{
    float a=0.7;
    printf("%.10f %.10f\n",0.7, a);
    return 0;
}

出力:
0.7000000000 0.6999999881

データ型を変更すると、 fダブル, 、印刷されます 等しい, これは、浮動小数点の定数が格納されているためです。 ダブル 浮いていない 長さ, 、double 精度は高く、float は精度が低く、double 値は次のように格納されます。 64 に格納されるビットバイナリ値と浮動小数点値 32 ビットバイナリの場合は、浮動小数点数をバイナリに変換する方法を見ればよくわかります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top