サイズの異なる可能性のあるレジスタとは別に、浮動小数点を非正規化 (cq flush-to-zero) して心配する必要があります (なぜ 0.1f を 0 に変更するとパフォーマンスが 10 倍低下するのですか? を参照してください) 。
これがもたらす可能性のある奇妙さを理解するために、次のコードを試してください。
float a = 0.000000000000000000000000000000000000000047683384;
const float b = 0.000000000000000000000000000000000000000047683384;
float aa = a, bb = b;
#define SUPPORT_DENORMALIZATION ({volatile double t=DBL_MIN/2.0;t!=0.0;})
printf("support denormals: %d\n",SUPPORT_DENORMALIZATION);
printf("a = %.48f, aa = %.48f\na==aa %d, a==0.0f %d, aa==0.0f %d\n",a,aa,a==aa,a==0.0f,aa==0.0f);
printf("b = %.48f, bb = %.48f\nb==bb %d, b==0.0f %d, bb==0.0f %d\n",b,bb,b==bb,b==0.0f,bb==0.0f);
次のいずれかが得られます:(ゼロへのフラッシュなしでコンパイル)
support denormals: 1
a = 0.000000000000000000000000000000000000000047683384, aa = 0.000000000000000000000000000000000000000047683384
a==aa 1, a==0.0f 0, aa==0.0f 0
b = 0.000000000000000000000000000000000000000047683384, bb = 0.000000000000000000000000000000000000000047683384
b==bb 1, b==0.0f 0, bb==0.0f 0
または: (でコンパイルgcc -ffast-math
)
support denormals: 0
a = 0.000000000000000000000000000000000000000000000000, aa = 0.000000000000000000000000000000000000000000000000
a==aa 1, a==0.0f 1, aa==0.0f 1
b = 0.000000000000000000000000000000000000000047683384, bb = 0.000000000000000000000000000000000000000000000000
b==bb 1, b==0.0f 0, bb==0.0f 1
もちろん、その最後の行は奇妙なものb==bb && b!=0.0f && bb==0.0f
です。これは本当です。
したがって、浮動小数点値の比較についてまだ考えている場合は、少なくとも小さな値には近づかないでください。
doubleの代わりにfloatを使用しているため、これに関するいくつかのコメントをオフセットするように更新します。これはdoubleでも機能しますが、定数を以下DBL_MIN
のどこかに設定する必要があります1e-309
。
以下のいくつかのコメントに関連するコードサンプルを更新します。これは、問題が double にも存在し、比較が矛盾する可能性があることを示しています (ゼロへのフラッシュが有効になっている場合)。
double a;
const double b = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001225;
const double c = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225;
printf("b==c %d\n",b==c);
a = b;
printf("assigned a=b: a==b %d\n",a==b);
a = c;
printf("assigned a=c: a==b %d\n",a==b);
出力:
b==c 0
assigned a=b: a==b 1
assigned a=c: a==b 1
この問題は最後の行に示されています。これは、 を割り当てたa==b
後に false になると単純に予想される場所です。a=c
c!=b