【问题标题】:Is there an advantage to using a bitwise operation opposed to dividing by 2 to find the median of an array? [duplicate]使用按位运算而不是除以 2 来查找数组的中位数是否有优势? [复制]
【发布时间】:2014-07-13 12:58:33
【问题描述】:

例如:

除以 2

int med = lo + (hi - lo) / 2;

按位右移

int med = lo + hi >>> 1;

我想知道,使用按位运算而不是除以2 有什么特别的优势吗?使用按位运算是否提供更有效或更可靠的计算?

我很想知道,因为java.util.Arrays 在执行二进制搜索时使用了按位移位。

【问题讨论】:

  • 注意,您的第二个表达式假定lo + hi 永远不会因为溢出以外的任何原因为负数。如果lo 为-2 且hi 为0,则med 将等于Integer.MAX_VALUE 而不是-1。
  • @cHao 是的,好电话。在这种情况下,它只会由溢出引起。我很想知道,我更新了我的 OP 以反映这一点,因为 java.util.Arrays 在执行二进制搜索时使用按位运算。

标签: java arrays bit-manipulation


【解决方案1】:

不太可能

您的编译器中有一个优化器,它知道如何在目标处理器架构的能力范围内尽可能快地进行乘法运算。所以有可能编译器已经做了这个优化。

通常可以将乘法或除法分解为一系列移位和加法,如果这一系列操作比乘法或除法更快,编译器将使用它。

【讨论】:

  • 对于 Java(至少在 Oracle 版本中),JITter 会执行此操作。如果有任何优化,编译器本身做的很少。
【解决方案2】:

如果您碰巧使用 2 的幂,在大多数(所有?)CPU 上,左右移位显然比乘法和除法运算要快。但是,它会降低某些阅读器和某些算法的代码清晰度。

关于这篇文章的更多信息:

Is shifting bits faster than multiplying and dividing in Java? .NET?

【讨论】:

    【解决方案3】:

    没有编译器会愚蠢到实际上为它发出一个完整的除法。但这并不意味着没有区别。有符号除以 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 有一点好处,而且真的没有坏处。那么为什么他们会使用它呢?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-07
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      相关资源
      最近更新 更多