2

From a friend of mine, I heard that the pow function is slower than its equivalent in simply multiplying the base by itself, the amount of times as its exponent. For example, according to him,

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

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

is slower than

#include <stdio.h>

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

As a novice, I would think they both compile at the same speed, and by the same logic, I would prefer the former for its typical pithiness. So, why is the former block of code slower than the latter one?

4

3 回答 3

5

pow(double,double)需要处理提升到任何幂,而不仅仅是基于整数的幂,或者尤其是2. 因此,它远比简单地将两个双精度值相乘复杂得多。

于 2013-06-27T19:19:02.693 回答
4

因为该pow函数必须实现一个更通用的算法,该算法必须适用于所有情况(特别是,它必须能够提升到任何可由 a 表示的有理指数double),而e*e只是一个简单的乘法,可以归结为一两个组装说明。

尽管如此,如果编译器足够聪明,它可能会自动替换你pow(e, 2.0)e*e无论如何(好吧,实际上在你的情况下它可能只会在编译时执行整个计算)。


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

#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(即在这两种情况下,它归结为在单个汇编指令中将值与自身相乘)。

于 2013-06-27T19:19:18.727 回答
0

这是一个(简单,注意评论) pow 实现。在通用时,它涉及许多分支,一个潜在的划分和对 exp、log、modf 的调用。

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

于 2013-06-27T19:20:38.817 回答