Math.abs 为 Integer.Min_VALUE 返回错误的值
此代码:
System.out.println(Math.abs(Integer.MIN_VALUE));
返回-2147483648
它不应该将绝对值返回为 ?2147483648
此代码:
System.out.println(Math.abs(Integer.MIN_VALUE));
返回-2147483648
它不应该将绝对值返回为 ?2147483648
Integer.MIN_VALUE
是 ,但 32 位整数可以包含的最大值是 。尝试以 32 位 int 表示将有效地“滚转到”到 。这是因为,当使用有符号整数时,两者的补码二进制表示和是相同的。然而,这不是问题,因为被认为超出了范围。-2147483648
+2147483647
+2147483648
-2147483648
+2147483648
-2147483648
+2147483648
有关此事的更多阅读,您可能需要查看维基百科上关于Two的补充的文章。
你指出的行为确实是违反直觉的。但是,此行为是由 javadoc 为 Math.abs(int)
指定的行为:
如果参数不为负,则返回该参数。如果参数为负数,则返回参数的否定。
也就是说,其行为应类似于以下 Java 代码:Math.abs(int)
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
也就是说,在否定的情况下,.-x
根据 JLS 第 15.15.4 节,等于 ,其中 是按位补码运算符。-x
(~x)+1
~
为了检查这听起来是否正确,让我们以 -1 为例。
整数值可以在Java中以十六进制形式记录(使用a或任何其他方法检查出来)。这样取取可以得到:-1
0xFFFFFFFF
println
-(-1)
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
所以,它的工作原理。
让我们现在就尝试使用 Integer.MIN_VALUE
。知道最低整数可以用 表示,即第一个位设置为 1,其余 31 位设置为 0,我们有:0x80000000
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
这就是返回的原因。另请注意,是 。Math.abs(Integer.MIN_VALUE)
Integer.MIN_VALUE
0x7FFFFFFF
Integer.MAX_VALUE
也就是说,我们该如何避免未来由于这种反直觉的回报值而产生的问题呢?
正如@Bombe所指出的那样,我们可以把我们的s投向以前。但是,我们必须要么int
long
int
Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
long
Math.abs(long)
Long.MIN_VALUE
Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
我们可以在任何地方使用 s,因为 BigInteger.abs()
确实总是返回一个正值。这是一个很好的替代方法,尽管比操作原始整数类型慢一些。BigInteger
我们可以为 编写自己的包装器,如下所示:Math.abs(int)
/**
* Fail-fast wrapper for {@link Math#abs(int)}
* @param x
* @return the absolute value of x
* @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)}
*/
public static int abs(int x) throws ArithmeticException {
if (x == Integer.MIN_VALUE) {
// fail instead of returning Integer.MAX_VALUE
// to prevent the occurrence of incorrect results in later computations
throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)");
}
return Math.abs(x);
}
int positive = value & Integer.MAX_VALUE
Integer.MAX_VALUE
0
Integer.MIN_VALUE
)最后要注意的是,这个问题似乎已经知道了一段时间。例如,请参阅有关相应查找虫规则的此条目。