Java,将(低+高)>> 1溢出?

时间:2016-03-29 23:31:57

标签: java overflow average bitwise-operators

我知道>>用于签名,>>>用于无符号

类似的问题没有回答我的问题:

Java, will (low + high) >>> 1 overflow?

Safe integer middle value formula

根据第二个链接,为什么他们得出结论: avg = (low & high) + ((low ^ high) >> 1);会避免溢出吗?

为什么他们不能仅使用它:(low + high) >> 1

(这是用于java中的二进制搜索)

1 个答案:

答案 0 :(得分:1)

是的,如果总和足够高,(low + high) >> 1可能会溢出。如您所知,>>>用于无符号,因此它总是在最重要的一侧以0移位。如果它溢出,这非常重要。

即使有溢出,使用(low + high)的技巧仍然是保留信息。如果它确实溢出,那么最大可能的数学和仍然是Integer.MAX_VALUE * 2,如果Java有一个,它仍然可以表示为无符号int。但是,当使用无符号右移运算符>>>除以2时,我们可以将和视为无符号整数。当1向右移位时,我们可以将总和视为无符号int,“取消溢出”int

如果总和溢出,则此处使用>>将无效,因为它将溢出为负数,>>将在1中移位,保持值为负值。这导致不正确的平均计算(2个正数,其总和溢出将导致负平均值)。

无论您使用>>>还是>>,都有可能出现溢出问题。所以两者都可以溢出。但是只有>>>能很好地处理这个案子,正确地“解除”总和。

诀窍

avg = (low & high) + ((low ^ high) >> 1);

是计算总和可能溢出时的平均值的另一种方法。这完全避免了溢出。这将总和分为两部分 - “进位”位和“非进位”位。

使用加法时,转移到下一个更高有效位的位是两个位都设置的位 - low & high。通常另外,这些位必须向左移动,但我们正在计算2个数的平均值,所以我们最后也会向右移动。最终结果:这里没有转变。

如果位不同,则未携带的位为1或者如果位相同则为0 - 这是(low ^ high)来自的位置(XOR) 。通常另外,这些位不会移位,但我们正在计算2个数的平均值,所以我们最后也会向右移位。此转变显示为>> 1&^运算符不会溢出,因此>>在这里可以正常工作。

示例:平均值1100(12)和1010(10)

1100 & 1010 = 1000
1100 ^ 1010 = 0110, 0110 >> 1 = 0011
1000 + 0011 = 1011 (11)