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()
,可用于除以任意数字:
返回第一个参数除以第二个参数的无符号商,其中每个参数和结果都被解释为无符号值
这可能有助于