为什么pow功能比简单操作慢?

时间:2013-06-27 19:16:12

标签: c gcc pow

从我的一个朋友那里,我听说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)
}

作为一个新手,我认为他们都以相同的速度编译,并且按照相同的逻辑,我更喜欢前者的典型精神。那么,为什么前一段代码比后一段慢?

3 个答案:

答案 0 :(得分:5)

pow(double,double)需要处理提升任何权力,而不仅仅是基于整数的权力,尤其是2。因此,它比仅仅进行两个双值的简单乘法要复杂得多。

答案 1 :(得分:3)

因为pow函数必须实现一个更通用的算法,该算法必须适用于所有情况(特别是,它必须能够升级到{{>> 指数可由{表示{1}}),而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 ++ 4.7.3)并使用g++ -O3 -c pow.c反汇编输出我得到:

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 pow2,它发出了一个valuexvalue(即在两种情况下,它都归结为单个汇编指令中值与其自身的乘法)。

答案 2 :(得分:0)

Here is one (simple, heed the comment) pow implementation。在通用中,它涉及许多分支,一个潜在的分支,并调用exp,log,modf ..

另一方面,乘法是在大多数高CPU上的单个指令(给予或接受)。