25

我需要多次检查两个整数是否在零的同一侧。我不在乎它是正面还是负面,只是它是同一面......而且性能很重要。

目前我正在这样做:

if (int1 == 0 || int2 == 0) {
    // handle zero
} else if ((int1 ^ int2) > 0) {
    // different side
} else {
    // same side
}

这比更明显的速度提高了 30%(用caliper测试):

if ((int1 > 0 && int2 > 0) || (int1 < 0 && int2 < 0)) {

可以做得更快吗?

如果有人想查看我用于 30% 的测试框架,它就在这里。我用卡尺 0.5-rc1

注意:所有这些解决方案基本上都检查第一位,对于零与正数相同。因此,如果这适用于您的应用程序,则无需进行零检查。

基准清单:

  • XOR:带有错误修复的原始答案
  • 如果:明显的((&&)||(&&))解决方案
  • 位: @hatchet 的解决方案(>>31) == (>>31)
  • BitAndXor: @greedybuddha 的解决方案(0x80000000)
  • BitAndEquals: @greedybuddha 的解决方案修改为==不使用^
  • XorShift: @aaronman 的解决方案(^)>>31 == 0

卡尺输出:

0% Scenario{vm=java, trial=0, benchmark=XOR} 1372.83 ns; ?=7.16 ns @ 3 trials
17% Scenario{vm=java, trial=0, benchmark=Ifs} 2397.32 ns; ?=16.81 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=Bits} 1311.75 ns; ?=3.04 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=XorShift} 1231.24 ns; ?=12.11 ns @ 5 trials
67% Scenario{vm=java, trial=0, benchmark=BitAndXor} 1446.60 ns; ?=2.28 ns @ 3 trials
83% Scenario{vm=java, trial=0, benchmark=BitAndEquals} 1492.37 ns; ?=14.62 ns @ 3 trials

  benchmark   us linear runtime
        XOR 1.37 =================
        Ifs 2.40 ==============================
       Bits 1.31 ================
   XorShift 1.23 ===============
  BitAndXor 1.45 ==================
BitAndEquals 1.49 ==================

vm: java
trial: 0

看起来@aaronman 是赢家

4

6 回答 6

13

(int1 ^ int2) >> 31 == 0 ? /*on same side*/ : /*different side*/ ; 这不一定能正确处理 0 我不确定在这种情况下你想做什么。
编辑:还想指出,如果这是在 c 而不是 java 中,它可以通过摆脱== 0布尔值在 c 中工作的方式来进一步优化,但情况会被切换

于 2013-06-05T22:16:11.043 回答
2
if (int1 == 0 || int2 == 0) {
    // handle zero
} else if ((int1 >> 31) == (int2 >> 31)) {
    // same side
} else {
    // different side
}

或者

if (int1 == 0 || int2 == 0) {
    // handle zero
} else if ((int1 & Integer.MIN_VALUE) == (int2 & Integer.MIN_VALUE)) {
    // same side
} else {
    // different side
}

两者的想法是相同的 - 除了符号位之外的所有内容,然后比较是否相等。我不确定哪个更快,右移(>>)或按位和(&)。

于 2013-06-05T22:07:55.743 回答
1

我会将它们比特转换为无符号整数,并对 MSB(最高有效位)进行异或运算 - 比任何比较(减法)或乘法都快得多

于 2013-06-05T21:42:02.987 回答
1

替代答案

比较符号位

return ((n >> 31) ^ (n2 >> 31) ) == 0 ? /* same */ : /* different */;

比较符号位的替代方法

return (((int1 & 0x80000000) ^ (int2 & 0x80000000))) == 0 ? /* same */ : /* different */;

我刚刚验证过,但 Op 的代码在int1 == int2. 如果它们相同,以下将始终打印不同。

if (int1 == 0 || int2 == 0) {
    // handle zero
} else if ((int1 ^ int2) < 0) {
    // same side
} else {
    // different side
}
于 2013-06-05T21:42:03.313 回答
0

另一个答案...

final int i = int1 ^ int2;

if (i == 0 && int1 == 0) {
    // both are zero
} else if (i & Integer.MIN_VALUE == Integer.MIN_VALUE) {
    // signs differ
} else {
    // same sign
}
于 2013-06-05T22:09:33.763 回答
-4
 int int1    = 3;
 int int2    = 4;
 boolean res = ( (int1 * int2) >= 0) ? true : false;

 System.out.println(res);
于 2013-06-05T21:35:03.193 回答