此代码:
System.out.println(Math.abs(Integer.MIN_VALUE));
返回-2147483648
它是否应该将绝对值返回为2147483648
?
答案 0 :(得分:82)
Integer.MIN_VALUE
是-2147483648
,但32位整数可以包含的最高值是+2147483647
。尝试在32位int中表示+2147483648
将有效地“翻转”到-2147483648
。这是因为,当使用有符号整数时,+2147483648
和-2147483648
的二进制补码二进制表示是相同的。但是,这不是问题,因为+2147483648
被视为超出范围。
有关此问题的更多信息,您可能需要查看Wikipedia article on Two's complement。
答案 1 :(得分:30)
你指出的行为确实是违反直觉的。但是,此行为是javadoc for Math.abs(int)
指定的行为:
如果参数不是负数,则返回参数。 如果参数为负数,则返回参数的否定。
也就是说,Math.abs(int)
应该像以下Java代码一样:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
即,在否定的情况下,-x
。
根据JLS section 15.15.4,-x
等于(~x)+1
,其中~
是按位补码运算符。
要检查这听起来是否正确,让我们以-1为例。
整数值-1
在Java中以十六进制表示为0xFFFFFFFF
(使用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
。
那就是说,我们怎样才能避免因为这种反直觉的回报价值而导致的问题?
我们可以as pointed out by @Bombe之前将int
投放到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
)作为最后一点,这个问题似乎已经有一段时间了。请参阅示例this entry about the corresponding findbugs rule。
答案 2 :(得分:11)
以下是Java doc对javadoc中的Math.abs()所说的内容:
请注意,如果参数等于 Integer.MIN_VALUE的值, 最负面可表示的int值, 结果就是那个相同的值 是否定的。
答案 3 :(得分:2)
要查看您期望的结果,请将Integer.MIN_VALUE
投射到long
:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
答案 4 :(得分:0)
2147483648不能存储在java中的整数中,其二进制表示与-2147483648相同。
答案 5 :(得分:0)
但(int) 2147483648L == -2147483648
有一个负数没有正数,因此没有正值。您将看到与Long.MAX_VALUE相同的行为。
答案 6 :(得分:0)
Math.abs不能始终使用大数字工作,我使用的是我7岁时学到的这个小代码逻辑!
if(Num < 0){
Num = -(Num);
}
答案 7 :(得分:0)
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
OR
Long.MIN_VALUE
引发异常。
https://bugs.openjdk.java.net/browse/JDK-8241805
我想看看是否传递了Long.MIN_VALUE或Integer.MIN_VALUE,将返回一个正值,而不是异常。