10

より複雑な比較を使用する必要がある浮動小数点計算エラーのトピックについて多くの議論があることに気付きました==。ただし、これらの記事はすべて、値が何らかの形で操作 (または二重計算) されていると想定しているようですが、非常に単純な定数コピーをカバーする例は見当たりませんでした。

次の点を考慮してください。

const double magical_value = -10;

class Test
{
    double _val;

public:
    Test()
        : _val(magical_value)
    {
    }

    bool is_special()
    {
        return _val == magical_value;
    }
};

私が理解している限り、magical_valueコンパイル時に設定して、その時点ですべての丸めが行われるようにする必要があります。その後、値をクラスにコピーして、元の値と比較する必要があります。そのような比較は安全であることが保証されていますか? または、コピーまたは比較すると、ここでエラーが発生する可能性がありますか?

代わりの比較や魔法の値の使用方法を提案しないでください。それは別のトピックです。私はちょうどこの仮定に興味があります。

編集:注意してください、一部のアーキテクチャでは、最適化により値が異なるサイズの浮動小数点レジスタにコピーされ、正確な値に違いが生じる可能性があることを少し心配しています。そのような危険性はありますか?

4

2 に答える 2

2

そのような比較は安全であることが保証されていますか? または、コピーまたは比較すると、ここでエラーが発生する可能性がありますか?

はい、安全です (これは、 で暗示されているコピー操作の要件です=)。ソースと宛先のタイプが同じである限り、心配する必要がある変換/プロモーションはありません。

ただし、正確でmagical_valueはなく概算であることに注意してください。10この近似は にコピーされ_valます。

const修飾子が与えられた場合、magical_value最適化されて取り除かれるか (最適化をオンにする必要があります)、そのまま使用される可能性があります (つまり、おそらくメモリが使い果たされることはありません)。

于 2012-06-13T08:58:50.247 に答える
0

サイズの異なる可能性のあるレジスタとは別に、浮動小数点を非正規化 (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=cc!=b

于 2012-06-13T09:52:33.470 に答える