gpt4 book ai didi

c++ - pow(NAN) 非常慢

转载 作者:可可西里 更新时间:2023-11-01 17:25:39 25 4
gpt4 key购买 nike

pow() 对 NaN 值的灾难性性能的原因是什么? As far as I can work out , 如果 float 学是使用 SSE 而不是 x87 FPU 完成的,NaN 应该不会对性能产生影响。

这对于基本操作似乎是正确的,但对于 pow() 则不然。我将 double 的乘法和除法比作平方然后取平方根。如果我用 g++ -lrt 编译下面的这段代码,我会得到以下结果:

multTime(3.14159): 20.1328ms
multTime(nan): 244.173ms
powTime(3.14159): 92.0235ms
powTime(nan): 1322.33ms

正如预期的那样,涉及 NaN 的计算需要相当长的时间。使用 g++ -lrt -msse2 -mfpmath=sse 编译会导致以下时间:

multTime(3.14159): 22.0213ms
multTime(nan): 13.066ms
powTime(3.14159): 97.7823ms
powTime(nan): 1211.27ms

NaN 的乘法/除法现在快得多(实际上比实数快),但是平方和开平方仍然需要很长时间。

测试代码(在VMWare 32bit OpenSuSE 10.2上用gcc 4.1.2编译,CPU是Core i7-2620M)

#include <iostream>
#include <sys/time.h>
#include <cmath>

void multTime( double d )
{
struct timespec startTime, endTime;
double durationNanoseconds;

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &startTime);

for(int i=0; i<1000000; i++)
{
d = 2*d;
d = 0.5*d;
}

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &endTime);
durationNanoseconds = 1e9*(endTime.tv_sec - startTime.tv_sec) + (endTime.tv_nsec - startTime.tv_nsec);
std::cout << "multTime(" << d << "): " << durationNanoseconds/1e6 << "ms" << std::endl;
}

void powTime( double d )
{
struct timespec startTime, endTime;
double durationNanoseconds;

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &startTime);

for(int i=0; i<1000000; i++)
{
d = pow(d,2);
d = pow(d,0.5);
}

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &endTime);
durationNanoseconds = 1e9*(endTime.tv_sec - startTime.tv_sec) + (endTime.tv_nsec - startTime.tv_nsec);
std::cout << "powTime(" << d << "): " << durationNanoseconds/1e6 << "ms" << std::endl;
}

int main()
{
multTime(3.14159);
multTime(NAN);

powTime(3.14159);
powTime(NAN);
}

编辑:

不幸的是,我对这个主题的了解非常有限,但我猜想 glibc pow() 从不在 32 位系统上使用 SSE,而是在 sysdeps/i386/中使用一些程序集fpu/e_pow.S。在最近的 glibc 版本中有一个函数 __ieee754_pow_sse2,但它在 sysdeps/x86_64/fpu/multiarch/e_pow.c 中,因此可能只适用于 x64。然而,所有这些在这里可能都无关紧要,因为 pow() 也是一个 gcc built-in function .如需轻松修复,请参阅 Z boson's answer .

最佳答案

“如果 float 学是使用 SSE 而不是 x87 FPU 完成的,NaN 应该不会对性能产生影响。”

我不确定这是从您引用的资源中得出的。无论如何,pow 是一个 C 库函数。它没有作为指令实现,即使在 x87 上也是如此。所以这里有 2 个不同的问题 - SSE 如何处理 NaN 值,以及 pow 函数实现如何处理 NaN 值。

如果 pow 函数实现对特殊值(如 +/-InfNaN)使用不同的路径,您可能期望一个 NaN 基数或指数的值,以快速返回值。另一方面,实现可能不会将此作为单独 情况处理,而只是依赖浮点运算将中间结果传播为 NaN 值。

从“Sandy Bridge”开始,减少或消除了许多与非规范化相关的性能损失。并非全部,因为作者描述了对 mulps 的惩罚。因此,可以合理地预期并非所有涉及 NaN 的算术运算都是“快速”的。某些架构甚至可能会恢复为微码来处理不同上下文中的 NaN

关于c++ - pow(NAN) 非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24929163/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com