此代码:
System.out.println(Math.abs(Integer.MIN_VALUE));
返回-2147483648
如果它没有返回绝对值为2147483648
?
此代码:
System.out.println(Math.abs(Integer.MIN_VALUE));
返回-2147483648
如果它没有返回绝对值为2147483648
?
Integer.MIN_VALUE
是-2147483648
,但一个32位整数可以包含最高值是+2147483647
。 试图代表+2147483648
在32位的int将有效地“翻转”到-2147483648
。 这是因为,用符号整数时,两个二进制补码表示+2147483648
和-2147483648
是相同的。 这不是一个问题,但是,由于+2147483648
被认为是超出范围。
有关这个问题有点多读书,你可能要检查出上两补维基百科的文章 。
你指出的行为的确,反直觉的。 然而,这种行为是由指定的所述一个的Javadoc Math.abs(int)
如果参数不是负数,则返回该参数。 如果参数为负数,则返回该参数的否定。
也就是说, Math.abs(int)
的行为应该像下面的Java代码:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
也就是说,在负的情况下, -x
。
根据JLS部15.15.4中, -x
是等于(~x)+1
,其中, ~
是按位求补运算符。
要检查这是否听起来很正确,我们先来-1为例。
整数值-1
是可以注意到为0xFFFFFFFF
在Java中的十六进制(检查了这一点与println
或任何其它方法)。 以-(-1)
因而给出:
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
因此,它的工作原理。
现在让我们尝试Integer.MIN_VALUE
。 知道的最小整可以表示0x80000000
,即,第一位设定为1,其余的31位设定为0,我们有:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
这就是为什么Math.abs(Integer.MIN_VALUE)
返回Integer.MIN_VALUE
。 还要注意的是0x7FFFFFFF
是Integer.MAX_VALUE
。
也就是说,我们怎样才能避免问题,是由于在未来,这是反直觉的返回值?
我们可以, 由@Bombe指出 ,铸就我们int
s到long
才。 然而,我们必须或者
int
s,这不起作用,因为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
。 我们可以使用BigInteger
到处都是,因为BigInteger.abs()
确实总是返回正值。 这是一个很好的选择,比操作原始整数类型慢强硬一点。
我们可以写我们自己的包装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
) 最后一点,这个问题似乎在一段时间内是已知的。 例如见有关相应FindBugs的规则该条目 。
以下是Java的医生说了Math.abs()中的javadoc :
请注意,如果参数等于Integer.MIN_VALUE,最负表示的int值的值,结果是相同的值,且为负。
要查看您所期待,把结果Integer.MIN_VALUE
要long
:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
2147483648不能被存储在java中的一个整数,它的二进制表示是相同的-2147483648。
但(int) 2147483648L == -2147483648
有其无正相当于所以没有为它正值一个负数。 你会看到与Long.MAX_VALUE相同的行为。