例如:
除以2
int med = lo + (hi - lo) / 2;
按位右移
int med = lo + hi >>> 1;
我想知道,使用按位运算而不是除以2
有什么特别的优势吗?使用按位运算是否可以提供更有效或更可靠的计算?
我很想知道因为java.util.Arrays在执行二进制搜索时使用了按位移位。
答案 0 :(得分:4)
不太可能
您的编译器中有一个优化器,它知道如何以目标处理器架构的速度倍增。所以编译器可能已经进行了这种优化。
通常可以将乘法或除法分解为一系列移位和加法,并且如果该系列操作将比乘法或除法更快,则编译器将使用它。
答案 1 :(得分:3)
如果您恰好使用2的幂,则左右移位明显比大多数(所有?)CPU上的乘法和除法运算快。但是,它会降低某些读取器和某些算法的代码清晰度。
关于这篇文章的更多信息:
Is shifting bits faster than multiplying and dividing in Java? .NET?
答案 2 :(得分:1)
没有编译器会如此愚蠢,以至于实际发出完全除法。但这并不意味着没有区别。一个2分的签名除法比右移更复杂,你必须做这样的事情:
mov edi, eax
shr eax, 31
add eax, edi
sar eax, 1
除非您能证明您除以2的数字是非负数。这需要证明hi >= lo
。在二分搜索中,这可能是可行的(如果在计算中间之前有if (hi < lo) return false;
或类似的东西)。
即使这样,分割方式仍然有3个操作,而换档版本则有2个。也许一个足够聪明的JIT编译器也可以看到它,但我们现在要求它越来越多。
Java开头几天的旧解释器当然不会做任何这样的事情,第一批JIT编译器也不会这样做。
因此编写hi + lo >>> 1
有一个小优势,并且确实没有缺点。那么为什么不会他们使用它?