检查两个整数是不是在 0 的同一侧的最快方法
Posted
技术标签:
【中文标题】检查两个整数是不是在 0 的同一侧的最快方法【英文标题】:Fastest way to check if two integers are on the same side of 0检查两个整数是否在 0 的同一侧的最快方法 【发布时间】:2013-06-01 18:10:39 【问题描述】:我需要多次检查两个整数是否在零的同一侧。我不在乎是正面的还是负面的,只要是同一面……而且表现很重要。
目前我正在这样做:
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))
可以做得更快吗?
If anyone wants to see the test framework I'm using for the 30%, it's here. I used caliper 0.5-rc1
注意:所有这些解决方案基本上都检查第一位,对于零与正数相同。因此,如果这适用于您的应用程序,则无需进行零检查。
基准列表:
XOR:带有错误修复的原始答案 如果: 明显的((&&)||(&&))
解决方案
Bits: @hatchet 的解决方案 (>>31) == (>>31)
BitAndXor: @greedybuddha 的解决方案(0x80000000)
BitAndEquals: @greedybuddha 的解决方案修改为使用==
而不是^
XorShift: @aaronman 的解决方案 (^)>>31 == 0
卡尺输出:
0% Scenariovm=java, trial=0, benchmark=XOR 1372.83 ns; ?=7.16 ns @ 3 trials
17% Scenariovm=java, trial=0, benchmark=Ifs 2397.32 ns; ?=16.81 ns @ 3 trials
33% Scenariovm=java, trial=0, benchmark=Bits 1311.75 ns; ?=3.04 ns @ 3 trials
50% Scenariovm=java, trial=0, benchmark=XorShift 1231.24 ns; ?=12.11 ns @ 5 trials
67% Scenariovm=java, trial=0, benchmark=BitAndXor 1446.60 ns; ?=2.28 ns @ 3 trials
83% Scenariovm=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 是赢家
【问题讨论】:
只是出于好奇,您如何检查速度?另外,我建议不要将零情况放在首位,因为它可能是最不可能的。 另外,同一个标志不应该是(int1 ^ int2) < 0
吗?
(int1 ^ int2) < 0
使用 2 个可以直接由硬件处理的操作。它不会比这更快。
我向你的精彩问题鞠躬,它应该被标记为“答案陷阱”。每个人都对这个问题进行了抨击,似乎被否决了。也许您的解决方案是唯一的?
这对 int1 == int2 有效吗?
【参考方案1】:
(int1 ^ int2) >> 31 == 0 ? /*on same side*/ : /*different side*/ ;
这不一定能正确处理 0 我不确定在这种情况下你想做什么。
编辑:还想指出,如果这是在 c 而不是 java 中,它可以通过摆脱 == 0
来进一步优化,因为布尔值在 c 中的工作方式,但情况会被切换
【讨论】:
我很确定这是最快的答案。除非有人想出更好的东西,否则我打算稍后再打勾。 那么应该有人给我一块饼干 我喜欢你的位移方式;) 为什么要转移? (int1 ^ int2) >= 0 ?相同:不同应该产生完全相同的结果【参考方案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
两者的想法是相同的 - 除了符号位之外的所有内容,然后比较是否相等。我不确定哪个更快,右移 (>>) 或按位与 (&)。
【讨论】:
@durron597 - 我已经把按位和版本放回去了。 第二个答案和@greedybuddha 的答案一样,呃,不是,但是我已经把他改成了那个哈哈。大编辑即将到来。 无法将int
转换为bool
,抱歉【参考方案3】:
我会将它们比特转换为无符号整数,并对 MSB(最高有效位)进行异或运算 - 比任何比较(进行减法)或乘法都快得多
【讨论】:
这个概念仍然存在,我不是 java 专家,但我相当确定你可以做类似的事情: (int1 & 0x8000000000000000L) ^ (int2 & 0x8000000000000000L) ,给出或接受语法问题和基于当然是你的整数大小。这里也提到了 - Best way to convert a signed integer to an unsigned long Java 中没有无符号整数 好的,所以除了选角之外,这与上面的建议有何不同?切换括号并说 (int1 ^ int2) & 0x8000000000000000 与 (int1 ^ int2) >> 31 完全相同。我称之为 dibs :)【参考方案4】:其他答案
比较符号位
return ((n >> 31) ^ (n2 >> 31) ) == 0 ? /* same */ : /* different */;
比较符号位的另一种方法
return (((int1 & 0x80000000) ^ (int2 & 0x80000000))) == 0 ? /* same */ : /* different */;
我刚刚验证过,但是当int1 == int2
时,Op 的代码是错误的。如果它们相同,以下将始终打印不同。
if (int1 == 0 || int2 == 0)
// handle zero
else if ((int1 ^ int2) < 0)
// same side
else
// different side
【讨论】:
但这只是 OP 的解决方案。 我认为应该快速且正确的替代答案。我现在看到 Ops 代码不是 好吧,应该是<=
或者> 0
-> 不同的一面优先
没错,但这会减慢速度,我的答案与您的基准相比如何?
我的我,相信更快,因为我只使用一次右移,而你使用两次,我改变了你的【参考方案5】:
另一个答案...
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
【讨论】:
【参考方案6】: int int1 = 3;
int int2 = 4;
boolean res = ( (int1 * int2) >= 0) ? true : false;
System.out.println(res);
【讨论】:
这并不能解决问题,你需要知道它是哪一个 - 零或同侧 抛开性能不谈,这并不总是有效的。见http://ideone.com/2QkTyK 现在试试:int int1 = 1200000000; int int2 = 1500000000;
以上是关于检查两个整数是不是在 0 的同一侧的最快方法的主要内容,如果未能解决你的问题,请参考以下文章