众所周知,为了计算整数x / 2,我们y=x/2;
对x * 2的写法与此类似;但是好的程序员会使用位操作来计算这一点。
他们只是做 y = x >> 1;
这两种方法之间有什么区别吗?差异是指所需的时间/空间/内存差异,或者两者完全相同(即x / 2由x >> 1实现)?
还有用其他数字而不是2进行乘法/除法的方式是否相同(即5*5 = 10*2 + 5*1 = 10 << 1 + 5 = 25
)?
在ridiculousfishblog上已经回答了这个问题:http : //ridiculousfish.com/blog/posts/will-it-optimize.html
- 除以2至右移
GCC会将2的整数除法转换为右移吗?
int halve_it(int x) {
return x / 2;
}
int halve_it(int x) {
return x >> 1;
}
右移位运算符等效于向负无穷大舍入的除法,但正常除法向零舍入。因此,对于奇数负数,建议的优化将产生错误的结果。
可以通过在移位之前将最高有效位添加到分子上来“固定”结果,而gcc可以做到这一点。
优秀的程序员可以让编译器优化其代码,除非它们会降低性能。
编辑:由于您需要官方消息,所以我们引用C99的标准基本原理文档。您可以在这里找到它:http : //www.open-std.org/jtc1/sc22/wg14/www/docs/C99RationaleV5.10.pdf
在C89中,涉及负操作数的整数除法可以按实现定义的方式向上或向下取整;目的是避免在运行时代码中产生开销,以检查特殊情况并强制执行特定行为。但是,在Fortran中,结果将始终截断为零,并且数字编程社区似乎可以接受这种开销。因此,C99现在需要类似的行为,这应该有助于将代码从Fortran移植到C。本文档§7.20.6.2中的表说明了所需的语义。
您的优化在C89中应该是正确的,因为它可以让编译器按需进行。但是,C99引入了新的约定以符合Fortran代码。这是除法运算符的期望示例(始终来自同一文档):
不幸的是,您的优化不符合C99标准,因为对于x = -1,它不能给出正确的结果:
#include <stdio.h>
int div8(int x)
{
return x/3;
}
int rs8( int x )
{
return x >> 3;
}
int main(int argc, char *argv[])
{
volatile int x = -1;
printf("div : %d \n", div8(x) );
printf("rs : %d \n", rs8(x) );
return 0;
}
Result:
div : 0
rs : -1
[Finished in 0.2s]
如果看一下已编译的代码,您会发现一个有趣的区别(与g ++ v4.6.2一起编译):
0040138c <__Z4div8i>:
40138c: 55 push %ebp
40138d: 89 e5 mov %esp,%ebp
40138f: 8b 45 08 mov 0x8(%ebp),%eax
401392: 85 c0 test %eax,%eax
401394: 79 03 jns 401399 <__Z4div8i+0xd>
401396: 83 c0 0f add $0x7,%eax
401399: c1 f8 04 sar $0x3,%eax
40139c: 5d pop %ebp
40139d: c3 ret
0040139e <__Z3rs8i>:
40139e: 55 push %ebp
40139f: 89 e5 mov %esp,%ebp
4013a1: 8b 45 08 mov 0x8(%ebp),%eax
4013a4: c1 f8 03 sar $0x3,%eax
4013a7: 5d pop %ebp
4013a8: c3 ret
line上401392
有一条test
指令,该指令将检查奇偶校验位,如果数字为负,则将1 << (n-1) = 7
在右移3个单位之前加到x上。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句