アサーションは、flush-to-zero および/または denormalized-is-zero モードでは失敗します (例: -mfpmath=sse、-fast-math などでコンパイルされたコードだけでなく、Intel のような既定のコンパイラやアーキテクチャのヒープでも)。 C++ コンパイラ) f が非正規化されている場合。
ただし、そのモードで非正規化されたフロートを生成することはできませんが、シナリオは引き続き可能です。
a) 非正規化フロートは外部ソースから取得されます。
b) 一部のライブラリは、FPU モードを改ざんしますが、関数呼び出しのたびに FPU モードを元に戻すことを忘れる (または意図的に回避する) ため、呼び出し元が正規化を一致させない可能性があります。
以下を出力する実際の例:
f = 5.87747e-39
f2 = 5.87747e-39
f = 5.87747e-39
f2 = 0
error, f != f2!
この例は VC2010 と GCC 4.3 の両方で機能しますが、VC はデフォルトで数学に SSE を使用し、GCC はデフォルトで数学に FPU を使用すると想定しています。それ以外の場合、この例では問題を説明できない場合があります。
#include <limits>
#include <iostream>
#include <cmath>
#ifdef _MSC_VER
#include <xmmintrin.h>
#endif
template <class T>bool normal(T t)
{
return (t != 0 || fabsf( t ) >= std::numeric_limits<T>::min());
}
void csr_flush_to_zero()
{
#ifdef _MSC_VER
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#else
unsigned csr = __builtin_ia32_stmxcsr();
csr |= (1 << 15);
__builtin_ia32_ldmxcsr(csr);
#endif
}
void test_cast(float f)
{
std::cout << "f = " << f << "\n";
double d = double(f);
float f2 = float(d);
std::cout << "f2 = " << f2 << "\n";
if(f != f2)
std::cout << "error, f != f2!\n";
std::cout << "\n";
}
int main()
{
float f = std::numeric_limits<float>::min() / 2.0;
test_cast(f);
csr_flush_to_zero();
test_cast(f);
}