[英]Java, will (low + high) >> 1 overflow?
我知道>>
用于已签名,而>>>
用于未签名
没有回答我的问题的类似问题:
根据第二个链接,他们为什么得出结论: avg = (low & high) + ((low ^ high) >> 1);
会避免溢出吗?
为什么他们不能直接使用它 : (low + high) >> 1
?
(这是用于java中的二进制搜索)
是的, (low + high) >> 1
如果总和足够高,可能会溢出。 如您所知, >>>
用于无符号,因此它始终会在最重要的一侧移动0
。 事实证明,这在它确实溢出时非常重要。
即使有溢出,使用(low + high)
的技巧是仍然保留信息。 如果它确实溢出,最大可能的数学总和仍然是Integer.MAX_VALUE * 2
,如果 Java 有一个 unsigned int
,它仍然可以表示为 unsigned int
。 但是,再除以2,当使用无符号向右移位运算,我们可以把之作为一个unsigned int, >>>
。 当右移1
,这让我们将总和视为 unsigned 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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.