提问人:aganm 提问时间:10/25/2023 最后编辑:Peter Cordesaganm 更新时间:10/26/2023 访问量:62
如何使 SIMD 除以零得到零?(86-64 版)
How to make SIMD divisions by zero give zero? (x86-64)
问:
我有我想除以的浮点数,其中一些可能是零。我怎样才能使除以零,当它们发生时,在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'
}
答:
3赞
Peter Cordes
10/25/2023
#1
没有 MXCSR 设置可以做到这一点,您需要额外的几条指令(针对除数和/或结果)来屏蔽除数输入所在的元素。cmpps
andps
andnps
==0.0f
除以零产生 +-无穷大,如果被除数也为零,则产生 NaN。Flush To Zero 没有次正态输出。
启用 DAZ 将使亚正常现象完全正确,并为您提供 NaN 而不是零股息。对于非零归一化除数,您仍然会使用次正态除数溢出到 +-Infinity。0 / subnornal
0.0f
0.0f
FTZ(Flush To Zero)仅在结果不正常时才执行任何操作。它禁用了逐渐的下溢;这是发生刷新的唯一情况,而不是会引起其他 FP 异常的其他情况。DAZ(非正态为零)只对次正态(又名非正态)做任何事情。
评论
0赞
Andrey Semashev
10/26/2023
你可以用 ++ 代替。的参数将是除法结果和除数,因此除数中的零元素将替换除法结果中的 NaN 和无穷大元素。blendvps
andps
andnps
orps
blendvps
1赞
Andrey Semashev
10/26/2023
虽然,转念一想,如果替换值为零,则不需要混合,但单个就可以了。 但是,如果替换值不为零,则仍然有用。andps
blendvps
0赞
Peter Cordes
10/26/2023
@AndreySemashev:没错,替换是零,所以你只需要一个,或者像我的回答说的那样,而不是混合。andps
andnps
评论
0
0.0f
0.0f
1.0 / 0.0
NaN / 0.0