2 ^ n指数计算是否真的比位移效率低?

如果我做:

int x = 4; pow(2, x); 

那真的那么低效吗:

 1 << 4 

是。 一个简单的方法是编译以下两个执行相同操作的函数,然后查看反汇编。

 #include  #include  uint32_t foo1(uint32_t shftAmt) { return pow(2, shftAmt); } uint32_t foo2(uint32_t shftAmt) { return (1 << shftAmt); } 

cc -arch armv7 -O3 -S -o - shift.c (我碰巧发现ARM asm更容易阅读,但如果你想要x86只是删除arch标志)

  _foo1: @ BB#0: push {r7, lr} vmov s0, r0 mov r7, sp vcvt.f64.u32 d16, s0 vmov r0, r1, d16 blx _exp2 vmov d16, r0, r1 vcvt.u32.f64 s0, d16 vmov r0, s0 pop {r7, pc} _foo2: @ BB#0: movs r1, #1 lsl.w r0, r1, r0 bx lr 

你可以看到foo2只需要2个指令而foo1需要多个指令。 它必须将数据移动到FP HW寄存器( vmov ),将整数转换为float( vcvt.f64.u32 )调用exp函数,然后将答案转换回uint( vcvt.u32.f64 )并移动它从FP HW返回到GP寄存器。

是。 虽然我不能说多少。 确定这一点的最简单方法是对其进行基准测试。

powfunction使用双倍……至少,如果它符合C标准。 即使该函数在看到2的基数时使用了bitshift,仍然会有测试和分支来达到这个结论,到那时你的简单位移将完成。 我们甚至还没有考虑过函数调用的开销。

为了等效,我假设您打算使用1 << x而不是1 << 4

也许编译器可以优化这两者,但是优化对pow的调用的可能性要小得多。 如果您需要以最快的方式计算2的幂,请通过移位来实现。

更新......因为我提到它很容易进行基准测试,所以我决定这样做。 我碰巧有Windows和Visual C ++,所以我用它。 结果会有所不同。 我的节目:

 #include  #include  #include  #include  LARGE_INTEGER liFreq, liStart, liStop; inline void StartTimer() { QueryPerformanceCounter(&liStart); } inline double ReportTimer() { QueryPerformanceCounter(&liStop); double milli = 1000.0 * double(liStop.QuadPart - liStart.QuadPart) / double(liFreq.QuadPart); printf( "%.3f ms\n", milli ); return milli; } int main() { QueryPerformanceFrequency(&liFreq); const size_t nTests = 10000000; int x = 4; int sumPow = 0; int sumShift = 0; double powTime, shiftTime; // Make an array of random exponents to use in tests. const size_t nExp = 10000; int e[nExp]; srand( (unsigned int)time(NULL) ); for( int i = 0; i < nExp; i++ ) e[i] = rand() % 31; // Test power. StartTimer(); for( size_t i = 0; i < nTests; i++ ) { int y = (int)pow(2, (double)e[i%nExp]); sumPow += y; } powTime = ReportTimer(); // Test shifting. StartTimer(); for( size_t i = 0; i < nTests; i++ ) { int y = 1 << e[i%nExp]; sumShift += y; } shiftTime = ReportTimer(); // The compiler shouldn't optimize out our loops if we need to display a result. printf( "Sum power: %d\n", sumPow ); printf( "Sum shift: %d\n", sumShift ); printf( "Time ratio of pow versus shift: %.2f\n", powTime / shiftTime ); system("pause"); return 0; } 

我的输出:

 379.466 ms 15.862 ms Sum power: 157650768 Sum shift: 157650768 Time ratio of pow versus shift: 23.92 

通常是的,因为位移是处理器的非常基本的操作。

另一方面,许多编译器优化代码,因此提升功率实际上只是一点点转移。

这取决于编译器,但一般情况下(当编译器不是完全脑死亡时)是,移位是一个CPU指令,另一个是函数调用,涉及保存当前状态设置堆栈帧,这需要很多说明。