我知道我可以使用右移执行除以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.
我想知道你们在代码中如何处理这个异常?你这个家伙做了一次检查吗?
答案 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)
在奇数情况下,两个操作都会导致结果中的楼层操作。
您可以进行检查,例如\
if ( isOdd(number) && isNegative(number) )
result++;