断言将在刷新为零和/或非规范化为零模式下失败(例如,使用 -mfpmath=sse、-fast-math 等编译的代码,但也会在默认的编译器和架构堆上,例如 Intel 的C++ 编译器)如果 f 是非规范化的。
但是,您不能在该模式下生成非规范化浮点数,但这种情况仍然是可能的:
a) 非规范化浮点数来自外部源。
b) 一些库篡改了 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);
}