java math.min value_java - Math.abs为Integer.Min_VALUE返回错误的值 - 堆栈内存溢出

您指出的行为确实是违反直觉的。

如果参数不为负,则返回参数。 如果参数为负,则返回参数取反。

也就是说, 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 〜x (~x)+1 ,其中~是按位补码运算符。

要检查听起来是否正确,我们以-1为例。

在Java中,整数值-1可以用十六进制表示为0xFFFFFFFF (请使用println或任何其他方法进行检查)。 取-(-1)因此得出:

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

因此,它有效。

知道最低的整数可以用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以前。 但是,我们必须

将它们Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)转换回int ,这不起作用,因为Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE) 。

或继续进行long s,以某种方式希望我们永远不要以等于Long.MIN_VALUE的值调用Math.abs(long) ,因为我们也有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 )

最后一点,这个问题似乎已经知道了一段时间。


版权声明:本文为weixin_39645249原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。