我有一些想要除法的浮点数,其中一些可能是零。我怎样才能做到在 x86-64 上除以零时,只返回零而不是 NaN?
我尝试设置 MXCSR 的 FZ 和 DAZ 标志,但无济于事。我误解了什么吗?齐平到零 + 非正规数 零不应该被零除得到零吗?
#include <stdio.h>
#include <xmmintrin.h>
int main()
{
#define CSR_FLUSH_TO_ZERO (1 << 15)
#define CSR_DENORMALS_ARE_ZERO (1 << 6)
unsigned int csr = _mm_getcsr();
csr |= CSR_FLUSH_TO_ZERO;
csr |= CSR_DENORMALS_ARE_ZERO;
_mm_setcsr(csr);
__m128 a = { 0 };
__m128 b = { 0 };
a = _mm_div_ps(a, b);
float f[4];
_mm_store_ps(f, a);
printf("%f\n", f[0]); // prints out 'nan'
}
没有 MXCSR 设置可以做到这一点,您需要额外的一对指令(
cmpps
和 andps
或 andnps
)来屏蔽除数输入为 ==0.0f
的元素。
除以零会产生 +-无穷大,如果被除数也为零,则产生 NaN,因此刷新到零不会产生次正常输出。
启用 DAZ 将使
0 / subnornal
将次正常值完全视为 0.0f
并为您提供 NaN 而不是 0.0f
且除数为零。对于非零标准化股息,您仍然会溢出到+-无穷大。
FTZ(清零)仅在结果不正常时才执行任何操作。它禁用逐渐下溢;这是唯一发生刷新的情况,而不是其他会引发其他 FP 异常的情况。 DAZ(非正规数为零)只对次正规(又名非正规)做任何事情。