以下哪一种技术是整数除2的最佳选择,为什么?

技巧1:

x = x >> 1;

技巧2:

x = x / 2;

这里x是整数。


当前回答

x / 2更清晰,x >> 1快不了多少(根据一个微基准测试,对于Java JVM快30%左右)。正如其他人所注意到的,对于负数,舍入略有不同,所以当您想处理负数时必须考虑这一点。一些编译器可能会自动将x / 2转换为x >> 1,如果他们知道这个数字不可能是负数(即使我无法验证这一点)。

即使x / 2可能不使用(慢)除法CPU指令,因为一些捷径是可能的,但它仍然比x >> 1慢。

(This is a C / C++ question, other programming languages have more operators. For Java there is also the unsigned right shift, x >>> 1, which is again different. It allows to correctly calculate the mean (average) value of two values, so that (a + b) >>> 1 will return the mean value even for very large values of a and b. This is required for example for binary search if the array indices can get very large. There was a bug in many versions of binary search, because they used (a + b) / 2 to calculate the average. This doesn't work correctly. The correct solution is to use (a + b) >>> 1 instead.)

其他回答

让你的意图更清楚……例如,如果你想除法,使用x / 2,并让编译器将其优化为shift运算符(或其他任何运算符)。

今天的处理器不会让这些优化对程序的性能产生任何影响。

Knuth说:

过早的优化是万恶之源。

所以我建议用x /= 2;

这样代码很容易理解,而且我认为这种形式的操作优化,对处理器来说不会有太大的区别。

我们有很多理由支持使用x = x / 2;以下是一些例子:

it expresses your intent more clearly (assuming you're not dealing with bit twiddling register bits or something) the compiler will reduce this to a shift operation anyway even if the compiler didn't reduce it and chose a slower operation than the shift, the likelihood that this ends up affecting your program's performance in a measurable way is itself vanishingly small (and if it does affect it measurably, then you have an actual reason to use a shift) if the division is going to be part of a larger expression, you're more likely to get the precedence right if you use the division operator: x = x / 2 + 5; x = x >> 1 + 5; // not the same as above signed arithmetic might complicate things even more than the precedence problem mentioned above to reiterate - the compiler will already do this for you anyway. In fact, it'll convert division by a constant to a series of shifts, adds, and multiplies for all sorts of numbers, not just powers of two. See this question for links to even more information about this.

简而言之,当你真正想要进行乘法或除法运算时,编写移位代码并没有什么好处,除了可能会增加引入错误的可能性。自从编译器不够聪明到在适当的时候优化这类事情到移位以来,已经过去了。

就CPU而言,位移运算比除法运算快。 然而,编译器知道这一点,并将适当地优化到它可以的程度, 因此,您可以以最有意义的方式编写代码,并且知道您的代码是有意义的 有效地运行。但是请记住,由于前面指出的原因,在某些情况下,无符号整型可以比整型更好地优化。 如果你不需要符号算术,那么不要包含符号位。

我同意其他答案,你应该支持x / 2,因为它的意图更清楚,编译器应该为你优化它。

然而,选择x / 2而不是x >> 1的另一个原因是,如果x是一个有符号int并且是负的,那么>>的行为是依赖于实现的。

ISO C99标准第6.5.7节第5项:

E1 >> E2的结果是E1位右移E2位位置。如果E1 无符号类型,或者E1有符号类型且值为非负值, 结果值为E1 /商的积分部分 2 e2。如果E1具有符号类型和负值,则结果值为 是由实现定义的。