2

浮動小数点数は実数ではないため、別々の計算で生成された 2 つの浮動小数点数が正確に等しいと期待することの危険性について、すでに多くの質問と回答があります。この質問は、等価性チェックを条件とする正確性に関するものではなく、それに基づくキャッシュに関するものです。

次のコードがあるとします。

if(myfloat != _last_float) {
    refresh_expensive_computation(myfloat);
    _last_float = myfloat;
}

この場合、等値比較は、冗長な作業を避けるために純粋に存在します。入力が変更されていない場合、コストのかかる計算を再度実行することは避けています (コストのかかる関数は決定論的であり、他の入力が変更されていないと仮定します)。

2 つが実際には等しい (つまり、浮動小数点ではなく実数で計算できた場合に等しくなる) が、そうでないと誤って検出された場合、最悪の場合、高価な計算を重複して実行しますが、プログラムの答えは依然として正しいです。私の知る限り、float のメモリ表現よりも広いレジスタで計算が行われた場合 (たとえば、80 ビットの fp レジスタが有効な場合の 32 ビット x86)、メモリ表現に変換された後に、それらが誤って等しいと比較される可能性があります。両方がビットごとに等しくなるようにします。その場合、違いはメモリ表現の精度を超えている必要があります。これは、私にとって重要な比較のためにイプシロン未満でなければなりません。

したがって、この浮動小数点の等価性の使用は安全であると断言します。最初の質問は、私が間違っているのでしょうか?

第 2 に、安全であると仮定した場合、誤って true を返すことは避けたいと思います。これは、コストのかかる計算を引き起こすためです。メモリ表現よりも幅の広いレジスタを持つマシンでそれを回避する 1 つの方法は、 memcmp を使用して強制的にメモリ表現を比較することです (NaN のセマンティクスはまったく同じではありません。ただし、キャッシングの場合は改善されます。または、+0 と -0 の場合は特殊なケースになる可能性があります)。ただし、その memcmp は、レジスタでの浮動小数点比較よりも遅くなります。プラットフォームがより広いレジスタを持っていることを検出する方法はありますか?

4

2 に答える 2

2

ほとんどのmemcmp実装には、レジスタの値が小さい最適化があるため、それを使用しても問題ありません。ただし、それに依存したくない場合は、次のようなこともできますreinterpret_cast<int>()compile_assert(sizeof(int) == sizeof(float))安全性を高めたい場合や、そのようなコマンドを含むライブラリ セットを使用している場合は、a を追加します。

NaN に注意してください。NaN は、たとえ別の NaN であっても、何にも等しくありません。このようにメモリを比較すると、同じように表示されますが、これはあなたが望んでいるように聞こえますが、すべての NaN が同じように扱われるようにコードを追加することをお勧めします。

于 2016-10-05T22:23:15.003 に答える
0

(C99) 一部の高精度 FP 数学が正確ではない比較を提供するのを避けるためvolatileに、最新のfloat値を使用するように計算を強制するために使用します。

if ((volatile float) myfloat != (volatile float) _last_float) {
  refresh_expensive_computation(myfloat);
  _last_float = myfloat;
}

注: を_先頭文字として使用し、変数名として文字を使用することは予約されています。改名したほうがいい_last_float

注: -0.0f は +0.0f と同じです。同じ値を持つこれらの異なるfloatが重要な場合は、 以外のコードが必要です!=

于 2016-10-06T02:34:05.567 に答える