Java 为什么JDK使用移位而不是乘法/除法?

Java 为什么JDK使用移位而不是乘法/除法?,java,optimization,collections,bit-manipulation,priority-queue,Java,Optimization,Collections,Bit Manipulation,Priority Queue,我有以下问题: 如果问到是否使用移位而不是乘法或除法,答案是,让JVM优化 示例如下: 例如,现在我在看jdk源代码,代码只对乘法和除法(有符号和无符号)使用移位 想当然地认为SO中的帖子是正确的答案,我想知道为什么在jdk中他们更喜欢通过转换来实现这一点 是不是一些与性能无关的细微细节?我怀疑这一定与上流/下流乘法和除法有关,但我不确定 有人有主意吗?使用移位是否能更好地处理微妙的溢出问题?还是仅仅是品味的问题?更多的是品味的问题。有些人非常习惯于二进制操作,因此他们更习惯于二进制操作(我个人

我有以下问题:

如果问到是否使用移位而不是乘法或除法,答案是,让JVM优化

示例如下:

例如,现在我在看jdk源代码,代码只对乘法和除法(有符号和无符号)使用移位

想当然地认为SO中的帖子是正确的答案,我想知道为什么在jdk中他们更喜欢通过转换来实现这一点

是不是一些与性能无关的细微细节?我怀疑这一定与上流/下流乘法和除法有关,但我不确定


有人有主意吗?使用移位是否能更好地处理微妙的溢出问题?还是仅仅是品味的问题?

更多的是品味的问题。有些人非常习惯于二进制操作,因此他们更习惯于二进制操作(我个人也在为自己编写的代码中使用这种操作)。然而,从性能的角度来看,这两种方法的行为是相同的(优化发生在编译时,因此使用移位将提高编译时间,但只占很小的一部分,您可以忽略这一点)


<>强>编辑< /强>,因为我经常会从我给出的每一个答案中得到一些新的东西:考虑一下。这就证明了为什么按二除法不能始终优化到换档。因此,只要java没有无符号类型,我上面的评论几乎是完全错误的。

我认为他们在这个特定示例中使用符号位。Java缺少无符号类型,因此无法对使用最高有效位的数字模拟
a>>1
,而
a/=2
。请注意,在整个示例中,代码如何仅使用
>>
。我可以合理地确定,这是为了充分利用整个位范围。

选择在Java中移位的一些正当理由:

  • 如果您可能正在非优化环境中运行,并且无法保证JIT编译器会为您进行必要的优化。这在当今可能很少见,但在某些情况下仍然可能发生
  • 如果你真的在做位操作而不是数字操作,那么在源代码中更清楚的是直接使用移位
  • 如果您想要无符号运算(例如,您可以轻松地进行无符号移位,但不能进行无符号除法)

除了在大多数系统上轮班比除法更快之外。
>
执行无符号运算,而除法不执行该运算。e、 g.如果需要两个值的中点,则需要使用
>
以避免溢出。(请参阅Arrays.binarySearch以获取类似的代码)

因此,对于像这样的微妙问题,如果没有shift运算符,就不可能编写没有bug的代码?@user384706当然可以:这里和那里的一个简单的三元运算符可以帮助您完成这项任务。然而,效率会受到影响。能不能举个例子?我很感兴趣knowing@user384706同样的原则-保存符号,进行无符号/有符号计算,修复结果。基本上任何计算都可以完成。@user384706我的意思是单独使用
n/2
是不可能的。我用
n/2
、条件、按位
以及按位
的组合来模拟它,例如,在优先级队列实现中,我假设原因3是为什么他们更喜欢移位?更一般地说,java中的JIT只能用移位代替除数2的幂,如果它能保证数字为正的话。如果没有,我们需要一个更复杂的例程(基本上可以归结为3个班次和一个无分支版本的add,或者一个branch和add+shift)我想知道你为什么在第一句话中提到性能。JVM不会优化它吗?这是我从另一句话中了解到的,所以我在OPDivision中提到的线程并不等于在输入为负时移位,JVM也不能总是证明输入为非负,在这种情况下,它必须承受除法的打击。@LouisWasserman:那么你是说我们必须始终使用移位运算符,因为JVM不会总是像我们期望的那样进行优化?在我链接到的So线程中,没有提到这一点,我相信我认为JVM在输入已知为非负的情况下可能是聪明的,但是(-1/2)==0和(-1>>1)=-1(和-1>>1==Integer.MAX_值),所以它不能用右移来代替2除法。如果你除以
n
,其中
n
总是2的幂,它不会知道这一点。如果你总是除以
m
,它清楚你在做什么。如果你除以
2
(一个常数)它将执行与
>
相同的操作,但不会执行
>>
,因为Java中没有未签名的2除法。