这段代码:
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
它被认为超出了范围。
要进一步了解这个问题,您可能需要查看关于二进制补码的 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 为例。
整数值-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
s 以某种方式希望我们永远不会调用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 规则的条目。
以下是 Java 文档对javadoc中 Math.abs() 的说明:
请注意,如果参数等于 Integer.MIN_VALUE 的值,即最负的可表示 int 值,则结果是相同的值,即为负。
要查看您期望的结果,请Integer.MIN_VALUE
转换为long
:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
2147483648在java中不能以整数形式存储,其二进制表示与-2147483648相同。
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 一个正值将被返回,而不是异常。
但是(int) 2147483648L == -2147483648
有一个负数没有正等价物,所以它没有正值。您将看到与 Long.MAX_VALUE 相同的行为。
Math.abs 并不总是适用于大数字 我使用我在 7 岁时学到的这个小代码逻辑!
if(Num < 0){
Num = -(Num);
}