为什么在Java中(high+;low)/2是错误的,但是(high+;low)>&燃气轮机&燃气轮机;1不是吗?
我知道为什么在Java中(high+;low)/2是错误的,但是(high+;low)>&燃气轮机&燃气轮机;1不是吗?,java,bit-manipulation,bitwise-operators,binary-search,Java,Bit Manipulation,Bitwise Operators,Binary Search,我知道>修复了溢出:当添加两个大的正长时,可能会以负数结束。有人能解释一下这种按位移位是如何神奇地解决溢出问题的吗?它与>有何不同 我的怀疑:我认为这与Java使用了两个恭维词有关,所以如果我们有额外的空间,溢出值是正确的数字,但因为我们没有,它变成了负数。因此,当你移动并用零划桨时,由于这两个赞美,它神奇地得到了修正。但我可能是错的,有点智慧的人必须加以证实。:) 它用零填充最上面的位,而不是用符号填充它们 int a = 0x40000000; (a + a) / 2 == 0xC00
>
修复了溢出:当添加两个大的正长时,可能会以负数结束。有人能解释一下这种按位移位是如何神奇地解决溢出问题的吗?它与>
有何不同
我的怀疑:我认为这与Java使用了两个恭维词有关,所以如果我们有额外的空间,溢出值是正确的数字,但因为我们没有,它变成了负数。因此,当你移动并用零划桨时,由于这两个赞美,它神奇地得到了修正。但我可能是错的,有点智慧的人必须加以证实。:) 它用零填充最上面的位,而不是用符号填充它们
int a = 0x40000000;
(a + a) / 2 == 0xC0000000;
(a + a) >>> 1 == 0x40000000;
简而言之,(高+低)>>1
是一种技巧,它使用未使用的符号位执行非负数的正确平均
假设
high
和low
都是非负的,我们可以确定最高位(符号位)为零
所以high
和low
实际上都是31位整数
high = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
low = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
当你把它们加在一起时,它们可能会“溢出”到顶部
high + low = 1000 0000 0000 0000 0000 0000 0000 0000
= 2147483648 as unsigned 32-bit integer
= -2147483648 as signed 32-bit integer
(high + low) / 2 = 1100 0000 0000 0000 0000 0000 0000 0000 = -1073741824
(high + low) >>> 1 = 0100 0000 0000 0000 0000 0000 0000 0000 = 1073741824
- 作为有符号32位整数,它是溢出的,并翻转为负数。因此,
是错误的,因为(高+低)/2
可能是负数高+低
- 作为无符号32位整数,总和是正确的。所需要的就是把它除以2
>
在使用无符号整数的语言中(如C和C++),由于输入可以是完整的32位整数,因此它变得更加复杂。一种解决方案是:low+((高-低)/2)
最后,要列举
>>
、>
和/
之间的差异:
是逻辑右移。它用零填充高位>
是算术右移。它用原始顶部位的副本填充上部its>
是分区/
将x>>>1
视为无符号整数并将其除以2。四舍五入x
将x>>1
视为有符号整数并将其除以二。它朝着负无穷远的方向旋转x
将x/2
视为有符号整数并将其除以2。它接近零x
我想你指的是?你怎么知道它解决了溢出问题?还有,什么溢出问题?Joshua Bloch告诉我:@JohnPristine:2的补码CPU对有符号和无符号整数执行加法的方式完全相同。。。唯一的区别在于
/2
。所以到那时为止,一切都是正确的。显然,因为有足够的位来表示和,所以有足够的位来表示商,>>1
就是这样做的。/2
出错的唯一原因是它试图更正符号,显然>>1
执行按位右移,这与无符号除以2相同。。。因此,它必须正确工作。我不确定这是否回答了你的问题……我的说法是否正确:“我认为这与Java使用两个赞美词有关,因此如果我们有额外的空间,溢出值是正确的数字,但因为我们没有,它变为负值。所以当你移动并用零划动时,它会神奇地得到修复。”?不确定何时使用>>>以及何时使用>>。我认为在这种情况下,我们选择>>>来修复可能的溢出(符号位溢出)问题。在>>和>>>之间选择的经验法则是什么?>>
是逻辑右移。它用零填充高位>
是算术右移。它用原始顶层位的副本填充上层位。从数学上讲,>1
将数字视为无符号,并除以2进行四舍五入<代码>>>1将数字视为已签名,并向下舍入到负无穷大<代码>/2将数字视为有符号的,并向零舍入。很好,答案永远不会变老。