数学。abs为Integer.Min_VALUE返回错误的值

时间:2022-07-19 21:18:45

This code:

这段代码:

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

Returns -2147483648

返回-2147483648

Should it not return the absolute value as 2147483648 ?

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

6 个解决方案

#1


75  

Integer.MIN_VALUE is -2147483648, but the highest value a 32 bit integer can contain is +2147483647. Attempting to represent +2147483648 in a 32 bit int will effectively "roll over" to -2147483648. This is because, when using signed integers, the two's complement binary representations of +2147483648 and -2147483648 are identical. This is not a problem, however, as +2147483648 is considered out of range.

整数。MIN_VALUE是-2147483648,但是32位整数可以包含的最高值是+2147483647。尝试在32位int中表示+2147483648将有效地“滚动”到-2147483648。这是因为,使用有符号整数时,+2147483648和-2147483648的两个补码二进制表示是相同的。但这不是问题,因为+2147483648被认为超出了范围。

For a little more reading on this matter, you might want to check out the Wikipedia article on Two's complement.

关于这个问题的更多阅读,您可能想要查看关于Two的补充的*文章。

#2


28  

The behaviour you point out is indeed, counter-intuitive. However, this behaviour is the one specified by the javadoc for Math.abs(int):

你所指出的行为确实是违反直觉的。但是,这个行为是javadoc为Math.abs(int)指定的:

If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned.

如果参数不是负面的,则返回该参数。如果参数为负,则返回该参数的否定。

That is, Math.abs(int) should behave like the following Java code:

也就是说,Math.abs(int)应该像下面的Java代码那样:

public static int abs(int x){
    if (x >= 0) {
        return x;
    }
    return -x;
}

That is, in the negative case, -x.

也就是-x。

According to the JLS section 15.15.4, the -x is equal to (~x)+1, where ~ is the bitwise complement operator.

根据JLS第15.4节,-x = (~x)+1,其中~为位补运算符。

To check whether this sounds right, let's take -1 as example.

为了检验这听起来是否正确,我们以-1为例。

The integer value -1 is can be noted as 0xFFFFFFFF in hexadecimal in Java (check this out with a println or any other method). Taking -(-1) thus gives:

整数值-1可以在Java中的十六进制中记为0xffffffffff(用println或任何其他方法检查一下)。——(1)因此给:

-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1

So, it works.

所以,它的工作原理。

Let us try now with Integer.MIN_VALUE . Knowing that the lowest integer can be represented by 0x80000000, that is, the first bit set to 1 and the 31 remaining bits set to 0, we have:

现在让我们来试试整数。MIN_VALUE。知道最小的整数可以用0x80000000表示,也就是说,第一个比特被设置为1,剩下的31个比特被设置为0,我们得到:

-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 
                     = 0x80000000 = Integer.MIN_VALUE

And this is why Math.abs(Integer.MIN_VALUE) returns Integer.MIN_VALUE. Also note that 0x7FFFFFFF is Integer.MAX_VALUE.

这就是为什么Math.abs(Integer.MIN_VALUE)返回Integer.MIN_VALUE的原因。还要注意,0x7FFFFFFF是Integer.MAX_VALUE。

That said, how can we avoid problems due to this counter-intuitive return value in the future?

也就是说,我们如何避免由于这种反直觉的回报价值在未来的问题?

  • We could, as pointed out by @Bombe, cast our ints to long before. We, however, must either

    正如@Bombe指出的那样,我们可以在很久以前将我们的ints抛给他人。然而,我们必须

    • cast them back into ints, which does not work because Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).
    • 将它们转换回int类型,这是无效的,因为是整数。MIN_VALUE = =(int)Math.abs((长)Integer.MIN_VALUE)。
    • Or continue with longs somehow hoping that we'll never call Math.abs(long) with a value equal to Long.MIN_VALUE, since we also have Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
    • 或者继续使用long语句,希望我们永远不会调用Math.abs(long),值为long。MIN_VALUE,因为我们还有Math.abs(Long.MIN_VALUE) = Long.MIN_VALUE。
  • We can use BigIntegers everywhere, because BigInteger.abs() does indeed always return a positive value. This is a good alternative, tough a bit slower than manipulating raw integer types.

    我们可以在任何地方使用biginteger,因为bigint .abs()确实总是返回一个正值。这是一个很好的选择,比处理原始整数类型要慢一些。

  • We can write our own wrapper for Math.abs(int), like this:

    我们可以为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);
}
  • Use a integer bitwise AND to clear the high bit, ensuring that the result is non-negative: int positive = value & Integer.MAX_VALUE (essentially overflowing from Integer.MAX_VALUE to 0 instead of Integer.MIN_VALUE)
  • 使用整数位并清除高位,确保结果是非负的:int positive = value & integer。MAX_VALUE(实质上是从整数溢出的。MAX_VALUE为0,而不是Integer.MIN_VALUE)

As a final note, this problem seems to be known for some time. See for example this entry about the corresponding findbugs rule.

最后,这个问题似乎已经知道一段时间了。例如,有关findbugs规则的条目。

#3


11  

Here is what Java doc says for Math.abs() in javadoc:

下面是Java doc在javadoc中对Math.abs()的描述:

Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.

注意,如果参数等于整数的值。MIN_VALUE,最负可表示的int值,结果是相同的值,这是负数。

#4


1  

To see the result that you are expecting, cast Integer.MIN_VALUE to long:

要查看预期的结果,请强制转换为整数。MIN_VALUE长:

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

#5


0  

2147483648 cannot be stored in an integer in java, its binary representation is the same as -2147483648.

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

#6


0  

But (int) 2147483648L == -2147483648 There is one negative number which has no positive equivalent so there is not positive value for it. You will see the same behaviour with Long.MAX_VALUE.

但是(int) 2147483648L = -2147483648有一个负数没有正等价,所以没有正值。您将看到与Long.MAX_VALUE相同的行为。

#1


75  

Integer.MIN_VALUE is -2147483648, but the highest value a 32 bit integer can contain is +2147483647. Attempting to represent +2147483648 in a 32 bit int will effectively "roll over" to -2147483648. This is because, when using signed integers, the two's complement binary representations of +2147483648 and -2147483648 are identical. This is not a problem, however, as +2147483648 is considered out of range.

整数。MIN_VALUE是-2147483648,但是32位整数可以包含的最高值是+2147483647。尝试在32位int中表示+2147483648将有效地“滚动”到-2147483648。这是因为,使用有符号整数时,+2147483648和-2147483648的两个补码二进制表示是相同的。但这不是问题,因为+2147483648被认为超出了范围。

For a little more reading on this matter, you might want to check out the Wikipedia article on Two's complement.

关于这个问题的更多阅读,您可能想要查看关于Two的补充的*文章。

#2


28  

The behaviour you point out is indeed, counter-intuitive. However, this behaviour is the one specified by the javadoc for Math.abs(int):

你所指出的行为确实是违反直觉的。但是,这个行为是javadoc为Math.abs(int)指定的:

If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned.

如果参数不是负面的,则返回该参数。如果参数为负,则返回该参数的否定。

That is, Math.abs(int) should behave like the following Java code:

也就是说,Math.abs(int)应该像下面的Java代码那样:

public static int abs(int x){
    if (x >= 0) {
        return x;
    }
    return -x;
}

That is, in the negative case, -x.

也就是-x。

According to the JLS section 15.15.4, the -x is equal to (~x)+1, where ~ is the bitwise complement operator.

根据JLS第15.4节,-x = (~x)+1,其中~为位补运算符。

To check whether this sounds right, let's take -1 as example.

为了检验这听起来是否正确,我们以-1为例。

The integer value -1 is can be noted as 0xFFFFFFFF in hexadecimal in Java (check this out with a println or any other method). Taking -(-1) thus gives:

整数值-1可以在Java中的十六进制中记为0xffffffffff(用println或任何其他方法检查一下)。——(1)因此给:

-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1

So, it works.

所以,它的工作原理。

Let us try now with Integer.MIN_VALUE . Knowing that the lowest integer can be represented by 0x80000000, that is, the first bit set to 1 and the 31 remaining bits set to 0, we have:

现在让我们来试试整数。MIN_VALUE。知道最小的整数可以用0x80000000表示,也就是说,第一个比特被设置为1,剩下的31个比特被设置为0,我们得到:

-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 
                     = 0x80000000 = Integer.MIN_VALUE

And this is why Math.abs(Integer.MIN_VALUE) returns Integer.MIN_VALUE. Also note that 0x7FFFFFFF is Integer.MAX_VALUE.

这就是为什么Math.abs(Integer.MIN_VALUE)返回Integer.MIN_VALUE的原因。还要注意,0x7FFFFFFF是Integer.MAX_VALUE。

That said, how can we avoid problems due to this counter-intuitive return value in the future?

也就是说,我们如何避免由于这种反直觉的回报价值在未来的问题?

  • We could, as pointed out by @Bombe, cast our ints to long before. We, however, must either

    正如@Bombe指出的那样,我们可以在很久以前将我们的ints抛给他人。然而,我们必须

    • cast them back into ints, which does not work because Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).
    • 将它们转换回int类型,这是无效的,因为是整数。MIN_VALUE = =(int)Math.abs((长)Integer.MIN_VALUE)。
    • Or continue with longs somehow hoping that we'll never call Math.abs(long) with a value equal to Long.MIN_VALUE, since we also have Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
    • 或者继续使用long语句,希望我们永远不会调用Math.abs(long),值为long。MIN_VALUE,因为我们还有Math.abs(Long.MIN_VALUE) = Long.MIN_VALUE。
  • We can use BigIntegers everywhere, because BigInteger.abs() does indeed always return a positive value. This is a good alternative, tough a bit slower than manipulating raw integer types.

    我们可以在任何地方使用biginteger,因为bigint .abs()确实总是返回一个正值。这是一个很好的选择,比处理原始整数类型要慢一些。

  • We can write our own wrapper for Math.abs(int), like this:

    我们可以为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);
}
  • Use a integer bitwise AND to clear the high bit, ensuring that the result is non-negative: int positive = value & Integer.MAX_VALUE (essentially overflowing from Integer.MAX_VALUE to 0 instead of Integer.MIN_VALUE)
  • 使用整数位并清除高位,确保结果是非负的:int positive = value & integer。MAX_VALUE(实质上是从整数溢出的。MAX_VALUE为0,而不是Integer.MIN_VALUE)

As a final note, this problem seems to be known for some time. See for example this entry about the corresponding findbugs rule.

最后,这个问题似乎已经知道一段时间了。例如,有关findbugs规则的条目。

#3


11  

Here is what Java doc says for Math.abs() in javadoc:

下面是Java doc在javadoc中对Math.abs()的描述:

Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.

注意,如果参数等于整数的值。MIN_VALUE,最负可表示的int值,结果是相同的值,这是负数。

#4


1  

To see the result that you are expecting, cast Integer.MIN_VALUE to long:

要查看预期的结果,请强制转换为整数。MIN_VALUE长:

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

#5


0  

2147483648 cannot be stored in an integer in java, its binary representation is the same as -2147483648.

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

#6


0  

But (int) 2147483648L == -2147483648 There is one negative number which has no positive equivalent so there is not positive value for it. You will see the same behaviour with Long.MAX_VALUE.

但是(int) 2147483648L = -2147483648有一个负数没有正等价,所以没有正值。您将看到与Long.MAX_VALUE相同的行为。