Math.abs返回Integer.MIN_VALUE的错误值Math.abs返回Integer.M

2019-05-13 09:27发布

此代码:

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

返回-2147483648

如果它没有返回绝对值为2147483648

Answer 1:

Integer.MIN_VALUE-2147483648 ,但一个32位整数可以包含最高值是+2147483647 。 试图代表+2147483648在32位的int将有效地“翻转”到-2147483648 。 这是因为,用符号整数时,两个二进制补码表示+2147483648-2147483648是相同的。 这不是一个问题,但是,由于+2147483648被认为是超出范围。

有关这个问题有点多读书,你可能要检查出上两补维基百科的文章 。



Answer 2:

你指出的行为的确,反直觉的。 然而,这种行为是由指定的所述一个的Javadoc 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为例。

整数值-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 。 还要注意的是0x7FFFFFFFInteger.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到处都是,因为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_VALUE0 ,而不是Integer.MIN_VALUE

最后一点,这个问题似乎在一段时间内是已知的。 例如见有关相应FindBugs的规则该条目 。



Answer 3:

以下是Java的医生说了Math.abs()中的javadoc :

请注意,如果参数等于Integer.MIN_VALUE,最负表示的int值的值,结果是相同的值,且为负。



Answer 4:

要查看您所期待,把结果Integer.MIN_VALUElong

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


Answer 5:

2147483648不能被存储在java中的一个整数,它的二进制表示是相同的-2147483648。



Answer 6:

(int) 2147483648L == -2147483648有其无正相当于所以没有为它正值一个负数。 你会看到与Long.MAX_VALUE相同的行为。



文章来源: Math.abs returns wrong value for Integer.Min_VALUE