Java 溢出,或不溢出,带>&燃气轮机&燃气轮机;操作人员

Java 溢出,或不溢出,带>&燃气轮机&燃气轮机;操作人员,java,binary,Java,Binary,我一直在使用intmid=low+((高-低)/2)计算中点,以防止潜在溢出。这是有意义的,因为(高-低)/2确保没有溢出。然而最近我发现了一种更快的方法。这是通过执行intmid=(低+高)>>1 显然,这也不会导致溢出。有人能解释一下原因吗?这与int mid=(低+高)/2非常相似,其中(低+高)导致溢出 System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) / 2); // -1 System.out.println((

我一直在使用
intmid=low+((高-低)/2)计算中点,以防止潜在溢出。这是有意义的,因为
(高-低)/2
确保没有溢出。然而最近我发现了一种更快的方法。这是通过执行
intmid=(低+高)>>1

显然,这也不会导致溢出。有人能解释一下原因吗?这与
int mid=(低+高)/2非常相似,其中
(低+高)
导致溢出

 System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) / 2); // -1
 System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) >>> 1); //2147483647

 System.out.println((Integer.MAX_VALUE + (Integer.MAX_VALUE - Integer.MAX_VALUE) / 2)); //2147483647
取决于您认为的“防溢出”。>>>运算符本身与溢出无关,它的表达式“低+高”可能会溢出

 System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) / 2); // -1
 System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) >>> 1); //2147483647

 System.out.println((Integer.MAX_VALUE + (Integer.MAX_VALUE - Integer.MAX_VALUE) / 2)); //2147483647
然而,在实践中,低/高将是列表或数组索引(读取:正整数),这就产生了所有差异

当添加低+高可以超过Integer.MAX_值(这是一个溢出)时,“>>>1”将参数视为无符号-因此,可能溢出并导致符号翻转的位可以通过移位usigned正确恢复,使结果返回到有符号int的范围内。

取决于您认为的“防溢出”。>>>运算符本身与溢出无关,它的表达式“低+高”可能会溢出

 System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) / 2); // -1
 System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) >>> 1); //2147483647

 System.out.println((Integer.MAX_VALUE + (Integer.MAX_VALUE - Integer.MAX_VALUE) / 2)); //2147483647
然而,在实践中,低/高将是列表或数组索引(读取:正整数),这就产生了所有差异


当添加低+高可以超过Integer.MAX_值(这是一个溢出)时,“>>>1”将参数视为无符号-因此,通过移位usigned,可以正确恢复可能溢出并导致符号翻转的位,将结果返回到有符号整数的范围内。

这可以有效地将所能表示的最大值加倍,从而防止溢出。与
>
不同,
>
不将符号位视为特殊的,因此就此操作而言,所有32位都代表数字

为了简化示例,让我们设想一个3字节的有符号类型,使用两个s-补码,就像Java对其整数类型所做的那样

0b000 = 0
0b001 = 1
0b010 = 2
0b011 = 3     // MAX
0b100 = -4    // MIN
0b101 = -3
0b110 = -2
0b111 = -1
在2的补码中,如果最左边的位为零,则将数字解释为正。如果最左边的位是1,则为负数;反转位并加上一个以获得幅值

  0b101 
= -(0b010 + 1) 
= -(2 + 1) 
= -3
。。。并且具有理想的特性,即将
011
增加到
100
以尽可能合理的方式溢出--
MAX
MIN
,并将
000
减少到
111
得到
-1

现在,如果我们在这个方案中加上3+2,我们会溢出到负片中:

0b011 + 0b010 = 0b101 
如果我们将其解释为无符号3位整数,则将转换为5(正确)。但由于Java将整数解释为2的补码,因此它将转换为-3

-3/2
给出了-1--不是我们想要的答案

-3>>1
给出了
0b101>>1
给出了
0b010
,这是2,我们想要的答案

因此,这里我们使用了
>>1
作为“除以2,将原始数字视为无符号整数”。当然,你只能用它除以二的幂

在Java8中,
Java.lang.Integer
Java.lang.Long
中有许多新方法将数字视为无符号。一种是
divideUnsigned()
,可用于除以任意数字:

返回第一个参数除以第二个参数的无符号商,其中每个参数和结果都被解释为无符号值

>
相比,您的代码的未来读者可以优先使用此选项

通过使用无符号安全方法处理整数,可以处理大于
整数.MAX_值的数字--
2^31-1
。但是如果超过
2^32-1
,仍然会溢出


Java数组或
列表
的最大值是
整数。最大值
,因此对于数组或列表索引,
(低+高)>>1
整数。divideUnsigned(低+高,2)
是安全的。

这通过有效地将所能表示的最大值加倍来防止溢出。与
>
不同,
>
不将符号位视为特殊的,因此就此操作而言,所有32位都代表数字

为了简化示例,让我们设想一个3字节的有符号类型,使用两个s-补码,就像Java对其整数类型所做的那样

0b000 = 0
0b001 = 1
0b010 = 2
0b011 = 3     // MAX
0b100 = -4    // MIN
0b101 = -3
0b110 = -2
0b111 = -1
在2的补码中,如果最左边的位为零,则将数字解释为正。如果最左边的位是1,则为负数;反转位并加上一个以获得幅值

  0b101 
= -(0b010 + 1) 
= -(2 + 1) 
= -3
。。。并且具有理想的特性,即将
011
增加到
100
以尽可能合理的方式溢出--
MAX
MIN
,并将
000
减少到
111
得到
-1

现在,如果我们在这个方案中加上3+2,我们会溢出到负片中:

0b011 + 0b010 = 0b101 
如果我们将其解释为无符号3位整数,则将转换为5(正确)。但由于Java将整数解释为2的补码,因此它将转换为-3

-3/2
给出了-1--不是我们想要的答案

-3>>1
给出了
0b101>>1
给出了
0b010
,这是2,我们想要的答案

因此,这里我们使用了
>>1
作为“除以2,将原始数字视为无符号整数”。当然,你只能用它除以二的幂

在Java8中,
Java.lang.Integer
Java.lang.Long
中有许多新方法将数字视为无符号。一种是
divideUnsigned()
,可用于除以任意数字:

返回第一个参数除以第二个参数的无符号商,其中每个参数和结果都被解释为无符号值

这可能有助于