右移以执行除以2开-1

时间:2010-01-27 00:52:24

标签: java algorithm

我知道我可以使用右移执行除以2。

为简单起见,采用4位数字系统

-1 - 1111
-2 - 1110
-3 - 1101
-4 - 1100
-5 - 1011
-6 - 1010
-7 - 1001
-8 - 1000
7  - 0111
6  - 0110
5  - 0101
4  - 0100
3  - 0011
2  - 0010
1  - 0001
0  - 0000

如果我尝试执行

6 / 2 = 0110 >> 1 = 0011 = 3
-6/ 2 = 1010 >> 1 = 1101 = -3

对+ ve和-ve数都有效

然而,当来到1

1 / 2 = 0001 >> 1 = 0000 = 0
-1/ 2 = 1111 >> 1 = 1111 = -1

似乎在-1中有一个特殊情况,因为右移然后将其移动到负无穷大。

目前,我需要对此进行特殊检查,因为我期待-1 / 2 = 0.

我想知道你们在代码中如何处理这个异常?你这个家伙做了一次检查吗?

6 个答案:

答案 0 :(得分:18)

任何负奇数都不起作用。然而,要回答你的问题,如果你知道你可以有负数,只需除以2.这将转变为jit /编译器修复的转变。

答案 1 :(得分:12)

@Anon在技术上是正确的。

但是,使用/运算符进行除法是最佳实践,并将微优化保留给JIT编译器。 JIT编译器能够通过常量优化除法作为移位/添加序列... ,这是执行平台的最佳选择

做这种事情(可能)是一种过早的优化,如果您的代码需要在多个Java平台上快速运行,那么它可能是一种反优化。

答案 2 :(得分:5)

我有一天感到无聊,并分析了两个人的权力的分歧和转变;以为我会在这里发帖给任何感兴趣的人。

在Windows上的HotSpot VM 1.6上,使用j /= 4在-100000000到100000000之间运行大约12秒,同时使用j = (j >= 0) ? j >> 2 : ~(~j+1 >> 2) + 1;仅运行2.5秒。

Linux上的OpenJDK VM 1.6分为5.5秒,轮班为1.5秒。

这表明JIT编译器并没有真正为2师的力量做任何事情。

海湾合作委员会设法优化分工,使其比翻转和转移更快。

~(~j+1 >> 2) + 1使用二进制补码来翻转正数,移位并将其翻转。

long j = 0;
for (long i = -100000000; i < 100000000; i++) {
    j = i;
    j /= 4;
}
System.out.println(j);`

vs

long j = 0;
for (long i = -100000000; i < 100000000; i++) {
    j = i;
    j = (j >= 0) ? j >> 2 : ~(~j+1 >> 2) + 1;
}
System.out.println(j);`

答案 3 :(得分:4)

如果你向右移动除以2,你总是向下“向上” - 如果是正数则朝向零,如果是负数则远离它。

如果这不是你想要的,你可以纠正它:

if (n & 1 > 0 && n < 0)
    result += 1;

答案 4 :(得分:4)

我不想这么说,但我不会在我的代码中处理这个,因为我不使用位移来进行乘法或除法。这让我觉得premature optimisation

为什么你认为你需要进行位移除法而不是更具可读性x / 2

答案 5 :(得分:0)

在奇数情况下,两个操作都会导致结果中的楼层操作。

  • 3/2 - &gt; floor(1.5)=&gt; 1
  • -3/2 - &gt; floor(-1.5)=&gt; -2

您可以进行检查,例如\

if ( isOdd(number) && isNegative(number) )
   result++;