Math.abs为Integer.Min_VALUE返回错误的值

时间:2011-03-26 19:07:33

标签: java absolute-value

此代码:

System.out.println(Math.abs(Integer.MIN_VALUE));

返回-2147483648

它是否应该将绝对值返回为2147483648

8 个答案:

答案 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的原因。另请注意,0x7FFFFFFFInteger.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);
}
  • 使用整数按位AND清除高位,确保结果为非负数: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,将返回一个正值,而不是异常。