归零非正规化 - 它可靠吗?
Flush-to-zero denormals - is it reliable?
对于信号处理,这一直是一个永远正确的问题,我仍在采取预防措施,每当可能发生异常时都添加一个小常量,例如:
float coef = 0.9f;
for (int i=0; i<cnt; i++) dst[i] = state = state * 0.9f + 1E-15f;
这显然不太理想,但过去我有很多问题,即使我尝试设置 FTZ,它实际上在某些计算机上显然不起作用。目前我正在像这样使用英特尔 IPP:
ippSetDenormAreZeros(b);
const int success = ippSetFlushToZero(b, NULL) == ippStsNoErr;
那么这有多可靠?有没有更好的办法?可靠的方法?不幸的是,我需要像所有来自 Core2duo、Windows 和 OSX 的古老 CPU 一样支持。但是,我通常使用 SSE2 和更新版本以及带有 -mfpmath=sse 和 -ffast-math 的 CLANG。
你说 "generally",但 x87 数学在 MXCSR 中没有任何等效的 FTZ/DAZ 位。只有 SSE/AVX 数学有这些。因此,如果您曾经使用 x87 数学编译遗留 32 位代码,您仍然可能会因次正规而变慢,因为硬件无法为它们禁用渐进下溢。 (而且 x87 在 NaN / Inf 上也很慢,而 SSE 不是。)
一般来说,link使用 -ffast-math
将使你的编译器 link 在 CRT 启动代码中设置那些 MXCSR 位,但在共享库函数中你不能假设除非您自己设置它们,否则它们将被设置。 (记住它们是基于线程的。我不确定新线程是从父线程继承的,还是从默认设置开始的)。
就具有独立 FP 数学的函数调用的即时更改和编译时重新排序而言,编译器可以假设除非您在 C 中使用 #pragma STDC FENV_ACCESS ON
,否则不会即时更改 FP 舍入模式。
但根据
,这仅存在于 C 中,而不存在于 C++ 中
实际上编译器在这方面可能并不完美。我真的不知道。希望其他人对此有更具体的答案。
但是,是的,在设置了 FTZ 和 DAZ 后,当 运行 SSE/AVX 数学指令时,现有的 x86 硬件将不会有任何 FP 辅助减速。
对于信号处理,这一直是一个永远正确的问题,我仍在采取预防措施,每当可能发生异常时都添加一个小常量,例如:
float coef = 0.9f;
for (int i=0; i<cnt; i++) dst[i] = state = state * 0.9f + 1E-15f;
这显然不太理想,但过去我有很多问题,即使我尝试设置 FTZ,它实际上在某些计算机上显然不起作用。目前我正在像这样使用英特尔 IPP:
ippSetDenormAreZeros(b);
const int success = ippSetFlushToZero(b, NULL) == ippStsNoErr;
那么这有多可靠?有没有更好的办法?可靠的方法?不幸的是,我需要像所有来自 Core2duo、Windows 和 OSX 的古老 CPU 一样支持。但是,我通常使用 SSE2 和更新版本以及带有 -mfpmath=sse 和 -ffast-math 的 CLANG。
你说 "generally",但 x87 数学在 MXCSR 中没有任何等效的 FTZ/DAZ 位。只有 SSE/AVX 数学有这些。因此,如果您曾经使用 x87 数学编译遗留 32 位代码,您仍然可能会因次正规而变慢,因为硬件无法为它们禁用渐进下溢。 (而且 x87 在 NaN / Inf 上也很慢,而 SSE 不是。)
一般来说,link使用 -ffast-math
将使你的编译器 link 在 CRT 启动代码中设置那些 MXCSR 位,但在共享库函数中你不能假设除非您自己设置它们,否则它们将被设置。 (记住它们是基于线程的。我不确定新线程是从父线程继承的,还是从默认设置开始的)。
就具有独立 FP 数学的函数调用的即时更改和编译时重新排序而言,编译器可以假设除非您在 C 中使用 #pragma STDC FENV_ACCESS ON
,否则不会即时更改 FP 舍入模式。
但根据
实际上编译器在这方面可能并不完美。我真的不知道。希望其他人对此有更具体的答案。
但是,是的,在设置了 FTZ 和 DAZ 后,当 运行 SSE/AVX 数学指令时,现有的 x86 硬件将不会有任何 FP 辅助减速。