这段代码:
System.out.println(Math.abs(Integer.MIN_VALUE));
退货 -2147483648
它不应该返回绝对值as2147483648
吗?
Answers:
Integer.MIN_VALUE
是-2147483648
,但32位整数可以包含的最大值是+2147483647
。尝试以+2147483648
32位int表示将有效地“翻转”到-2147483648
。这是因为,使用符号的整数时,两个补的二进制表示+2147483648
和-2147483648
是相同的。但是,这不是问题,因为+2147483648
超出了范围。
有关此问题的更多信息,您可能想查看Two的补语上的Wikipedia文章。
您指出的行为确实是违反直觉的。但是,此行为是javadocMath.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为例。
在Java中,整数值-1
可以用0xFFFFFFFF
十六进制表示(请使用aprintln
或任何其他方法进行检查)。以-(-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
在任何地方使用s,因为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规则,请参见此条目。
要查看您期望的结果,请强制转换Integer.MIN_VALUE
为long
:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
Math.abs
返回负数来解决反直觉的事实:Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
?此外,该行为已在API文档中明确记录。
Math.abs(long)
。对于我的错误,我深表歉意:我坚信Math.abs(long)
,当您将其显示为“查看请求者期望的结果”的简单方法时,便建议您将其用作修复程序。抱歉。
Java 15中对此进行了修复,它将成为一个int和long方法。他们将在课堂上
java.lang.Math and java.lang.StrictMath
方法。
public static int absExact(int a)
public static long absExact(long a)
如果通过
Integer.MIN_VALUE
要么
Long.MIN_VALUE
引发异常。
https://bugs.openjdk.java.net/browse/JDK-8241805
我想看看是否传递了Long.MIN_VALUE或Integer.MIN_VALUE,将返回一个正值,但不是异常。