这段代码:
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
。试图在32位int中表示+2147483648
将会有效地"循环回滚"到-2147483648
。这是因为,在使用带符号整数时,+2147483648
和-2147483648
的二进制补码表示是相同的。然而,+2147483648
被认为是超出范围的而不是问题。
如果想要更深入地了解这个问题,您可以查看Wikipedia关于二进制补码的文章。
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为例。
在Java中,整数值-1
可以表示为十六进制的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
。正如 @Bombe 指出的那样,我们可以在操作前将 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
。我们可以在任何地方使用 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规则的条目。
Integer.MIN_VALUE
转换为long
:System.out.println(Math.abs((long) Integer.MIN_VALUE));
Math.abs
返回负数的反直觉问题:Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
。 - bernard paulusArithmeticException
之外,它应该做什么?此外,该行为在API文档中得到了明确记录。 - BombeMath.abs(long)
来解决。很抱歉我的错误:我以为你提出了使用 Math.abs(long)
作为修复方法,而你只是简单地用它来“看到提问者期望的结果”。对不起。 - bernard paulus在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,是否会返回一个正值而不是异常。
在Java中,2147483648不能存储在整数中,它的二进制表示与-2147483648相同。
但是 (int) 2147483648L == -2147483648
。有一个负数没有正等价,因此它没有正值。您将在 Long.MAX_VALUE 中看到相同的行为。
Math.abs对于大数并不总是有效,我使用的是我7岁时学到的一点代码逻辑!
if(Num < 0){
Num = -(Num);
}
s
是什么? - aioobeNum
等于Integer.MIN_VALUE
,那么这会导致什么结果? - aioobe