我知道>>
用于签名,>>>
用于无符号
类似的问题没有回答我的问题:
Java, will (low + high) >>> 1 overflow?
Safe integer middle value formula
根据第二个链接,为什么他们得出结论:
avg = (low & high) + ((low ^ high) >> 1);
会避免溢出吗?
为什么他们不能仅使用它:(low + high) >> 1
?
(这是用于java中的二进制搜索)
答案 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)