浮点数运算执行时间

4
第一个数据集执行时间增加的原因是什么?汇编指令是相同的。
当DN_FLUSH标志未开启时,第一个数据集需要63毫秒,第二个数据集需要15毫秒。当DN_FLUSH标志开启时,第一个数据集需要15毫秒,第二个数据集需要约0毫秒。
因此,在两种情况下,第一个数据集的执行时间都要长得多。
有没有办法减少执行时间,使其接近于第二个数据集?
我正在使用C++ Visual Studio 2005,/arch:SSE2 /fp:fast在Intel Core 2 Duo T7700 @ 2.4Ghz Windows XP Pro上运行。
#define NUMLOOPS 1000000

// Denormal values flushed to zero by hardware on ALPHA and x86
// processors with SSE2 support. Ignored on other x86 platforms
// Setting this decreases execution time from 63 milliseconds to 16 millisecond
// _controlfp(_DN_FLUSH, _MCW_DN);

float denormal = 1.0e-38;
float denormalTwo = 1.0e-39;
float denormalThree = 1;

tickStart = GetTickCount();

// Run First Calculation Loop 
for (loops=0; loops < NUMLOOPS; loops++)
{
    denormalThree = denormal - denormalTwo;
}

// Get execution time
duration = GetTickCount()-tickStart;
printf("Duration = %dms\n", duration);

float normal = 1.0e-10;
float normalTwo = 1.0e-2;
float normalThree = 1;

tickStart = GetTickCount();

// Run Second Calculation Loop 
for (loops=0; loops < NUMLOOPS; loops++)
{
    normalThree = normal - normalTwo;
}

// Get execution time
duration = GetTickCount()-tickStart;
printf("Duration = %dms\n", duration);

3
你应该知道,GetTickCount() 函数用于计时代码的效果很差。它的粒度非常大,可能高达100毫秒,在不同的系统上也会有所不同。建议使用 QueryPerformanceCounter() 函数代替。 - John Dibling
QueryPerformanceCounter() 使用起来很麻烦...试试 timeGetTime()。另外,对于运行几秒钟或更长时间的事物,GetTickCount() 并不那么糟糕 - 只需注意精度即可。 - Inverse
顺便提一句,不要以为使用 /arch:SSE2 /fp:fast 就能让你的代码更快。对于我的代码来说,我发现 /fp:precise 并且使用 FP 栈实际上更快。同样地,不要认为浮点数比双精度浮点数更快。测试所有选项。 - Joe
2个回答

11
引用英特尔优化手册的话:
当SIMD浮点指令的输入操作数(这里包括使用SSE进行的标量算术运算)包含小于数据类型可表示范围的值时,会发生异常。这会导致显著的性能损耗。 SIMD浮点操作具有零清模式,其中结果不会下溢。因此,后续计算不会面临处理非规格化输入操作数的性能惩罚。
至于如何避免这种情况,如果无法清除非规格化数:尽力确保您的数据已适当缩放,并且您在第一次遇到非规格化数之前不会遇到它们。通常这意味着推迟应用某些比例因子,直到您完成所有其他计算为止。
或者,使用具有更大指数范围的double来进行计算,从而使遇到非规格化数的可能性大大降低。

2
顺便提一下,float 的非规格化极限大约为1.18e-38,而 double 的非规格化极限大约为2.225e-308。 - kennytm
3
使用二进制基数并避免近似值:单精度浮点数在 2 ** -126 处下溢,双精度浮点数在 2 ** -1022 处下溢。 - Stephen Canon

2

以下是Intel手册第1卷第10.2.3.3章节中的另一则引用:

清零模式与IEEE 754标准不兼容。IEEE强制要求对下溢进行掩码响应,以提供非规格化结果(请参见第4.8.3.2节“规格化和非规格化有限数字”)。清零模式主要是为了提高性能而设计的。通过稍微降低精度,可以在需要处理下溢且将下溢结果四舍五入为零可被接受的应用程序中实现更快的执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接