避免在C ++中使用非正规值

时间:2010-03-21 15:51:58

标签: c++ floating-point performance

在长时间搜索性能错误后,我读到了非正规浮点值。

显然,非规范化的浮点值可能是一个主要的性能问题,如此问题所示: Why does changing 0.1f to 0 slow down performance by 10x?

我有一个Intel Core 2 Duo,我使用-O2编译gcc。

那我该怎么办?我可以以某种方式指示g ++避免非正规值吗? 如果没有,我可以以某种方式测试float是否正常吗?

6 个答案:

答案 0 :(得分:23)

等待。在您做任何事情之前,您是否真的知道您的代码遇到了非正常值,并且它们对性能产生了可衡量的影响?

假设您知道,如果关闭非正常支持,您知道您使用的算法是否稳定吗?得到错误的答案速度提高10倍通常不是一个好的性能优化。

除了这些问题:

  • 如果您想检测非正常值以确认它们的存在,您有几个选项。如果您有C99标准库或Boost,则可以使用fpclassify宏。或者,您可以将数据的绝对值与最小正正常数进行比较。

  • 您可以将硬件设置为将非正常值刷新为零(FTZ),或将非正常输入视为零(DAZ)。最简单的方法是,如果在您的平台上得到适当支持,可能会使用C标头fesetenv( )中的fenv.h函数。但是,这是C标准中支持最少的功能之一,无论如何都具有固有的平台特性。您可能只想使用一些内联汇编来直接将FPU状态设置为(DAZ / FTZ)。

答案 1 :(得分:14)

您可以使用

测试浮点数是否正常
#include <cmath>

if ( std::fpclassify( flt ) == FP_SUBNORMAL )

(警告:我不确定这会在实践中全速执行。)

在C ++ 03中,这段代码在实践中对我有用,

#include <cmath>
#include <limits>

if ( flt != 0 && std::fabsf( flt ) < std::numeric_limits<float>::min() ) {
    // it's denormalized
}

要确定应用此位置,可以使用基于样本的分析器(如Shark,VTune或Zoom)来突出显示非正常值减慢的指令。微观优化,甚至超过其他优化,在没有前后分析的情况下完全没有希望。

答案 2 :(得分:7)

大多数数学协处理器都可以选择将非正规值截断为零。在x86上,它是MXCSR控制寄存器中的FZ(Flush to Zero)标志。检查您的CRT实现以获得支持功能以设置控制寄存器。它应该在<float.h>中,类似于_controlfp()。选项位通常在#defined符号中有“FLUSH”。

设置此项后,请仔细检查您的数学结果。无论如何,这是你应该做的事情,获得​​非正常情绪是健康问题的一个标志。

答案 3 :(得分:4)

要在gcc中使用(刷新为零)FTZ(假设默认情况下屏蔽了下溢):

#define CSR_FLUSH_TO_ZERO         (1 << 15)
unsigned csr = __builtin_ia32_stmxcsr();
csr |= CSR_FLUSH_TO_ZERO;
__builtin_ia32_ldmxcsr(csr);

如果名称不明显,__builtin_ia32_stmxcsr__builtin_ia32_ldmxcsr仅在您定位到x86处理器时才可用。 ARM,Sparc,MIPS等将使用这种方法各自需要单独的平台特定代码。

答案 4 :(得分:1)

作为对其他答案的补充,如果您确实遇到非正规浮点值问题,除了性能问题之外,您可能还会遇到精度问题。

检查是否可以重新构建计算以保持数字更大以避免精度和性能下降,这可能是一个好主意。

答案 5 :(得分:0)

你显然想要一些名为FTZ(Flush To Zero)和DAZ(Denormals Are Zero)的CPU指令。

我在音频网站上找到了这些信息,但缺少他们与英特尔文档的链接。它们显然是SSE2指令,所以它们应该支持支持它的AMD CPU。

我不知道你在GCC可以做些什么来以便携的方式强行推行。您始终可以编写内联汇编代码来使用它们。您可能必须强制GCC仅使用SSE2进行浮点数学运算。