繁体   English   中英

为什么pow函数比简单操作慢?

[英]Why is the pow function slower than simple operations?

从我的一个朋友那里,我听说pow函数比简单地乘以基数(即乘以其指数的次数)要慢得多。 例如,据他说,

#include <stdio.h>
#include <math.h>

int main () {
    double e = 2.71828
    e2 = pow (e, 2.0)
    printf("%le", e2)
}

比慢

#include <stdio.h>

int main() {
    double e = 2.71828
    e2 = e * e
    printf("%le", e2)
}

作为新手,我认为它们的编译速度和逻辑相同,因此我更喜欢前者的典型信奉度。 那么,为什么前一个代码块比后一个代码块慢?

pow(double,double)需要处理任何幂 ,而不仅仅是基于整数的幂,尤其是2 这样,它比仅对两个double值进行简单的乘法要复杂得多。

因为pow函数必须实现一个必须在所有情况下都可以使用的更通用的算法(特别是,它必须能够提升为double表示的任何有理指数),而e*e只是一个简单的乘法,它将沸腾精简到一两个汇编指令。

不过,如果编译器足够聪明,它可能会自动以e*e自动替换pow(e, 2.0) (嗯,实际上,在您的情况下,它可能只会在编译时执行整个计算)。


只是为了好玩,我进行了一些测试:编译以下代码

#include <math.h>

double pow2(double value)
{
    return pow(value, 2.);
}

double knownpow2()
{
    double e=2.71828;
    return pow(e, 2.);
}

double valuexvalue(double value)
{
    return value*value;
}

double knownvaluexvalue()
{
    double e=2.71828;
    return e*e;
}

使用g++ -O3 -c pow.c (g ++ 4.7.3)并使用objdump -d -M intel pow.o分解输出,我得到:

0000000000000000 <_Z4pow2d>:
   0:   f2 0f 59 c0             mulsd  xmm0,xmm0
   4:   c3                      ret    
   5:   66 66 2e 0f 1f 84 00    data32 nop WORD PTR cs:[rax+rax*1+0x0]
   c:   00 00 00 00 

0000000000000010 <_Z9knownpow2v>:
  10:   f2 0f 10 05 00 00 00    movsd  xmm0,QWORD PTR [rip+0x0]        # 18 <_Z9knownpow2v+0x8>
  17:   00 
  18:   c3                      ret    
  19:   0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]

0000000000000020 <_Z11valuexvalued>:
  20:   f2 0f 59 c0             mulsd  xmm0,xmm0
  24:   c3                      ret    
  25:   66 66 2e 0f 1f 84 00    data32 nop WORD PTR cs:[rax+rax*1+0x0]
  2c:   00 00 00 00 

0000000000000030 <_Z16knownvaluexvaluev>:
  30:   f2 0f 10 05 00 00 00    movsd  xmm0,QWORD PTR [rip+0x0]        # 38 <_Z16knownvaluexvaluev+0x8>
  37:   00 
  38:   c3                      ret    

因此,在编译器已经知道所有涉及的值的地方,它只是在编译时执行了计算。 对于pow2valuexvalue它发出单个mulsd xmm0,xmm0 (即,在两种情况下,都归结为在单个汇编指令中值与自身的乘积)。

这是一个(简单,请注意注释)pow实现 在泛型中,它涉及多个分支以及一个潜在的分支,并调用exp,log,modf ..

另一方面,在大多数更高的CPU上,乘法是一条指令(给定或取指令)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM