use*_*319 77 java absolute-value
这段代码:
System.out.println(Math.abs(Integer.MIN_VALUE));
Run Code Online (Sandbox Code Playgroud)
返回 -2147483648
它不应该返回绝对值2147483648
吗?
ber*_*lus 33
你指出的行为确实是违反直觉的.但是,此行为是由javadocMath.abs(int)
指定的行为:
如果参数不是负数,则返回参数.如果参数为负数,则返回参数的否定.
也就是说,Math.abs(int)
应该表现得像以下Java代码:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
Run Code Online (Sandbox Code Playgroud)
也就是说,在否定的情况下,-x
.
根据JLS第15.15.4节,-x
它等于(~x)+1
,其中~
是按位补码运算符.
要检查这听起来是否正确,让我们以-1为例.
整数值-1
可以0xFFFFFFFF
在Java中以十六进制表示(使用println
或任何其他方法检查).以-(-1)
这样得到:
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
Run Code Online (Sandbox Code Playgroud)
所以,它的工作原理.
让我们现在尝试一下Integer.MIN_VALUE
.知道最低整数可以表示0x80000000
,即第一位设置为1而其余31位设置为0,我们有:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
Run Code Online (Sandbox Code Playgroud)
这就是Math.abs(Integer.MIN_VALUE)
回报的原因Integer.MIN_VALUE
.还要注意的0x7FFFFFFF
是Integer.MAX_VALUE
.
也就是说,我们怎样才能避免将来由于这种反直觉的回报价值而产生的问题呢?
正如@Bombe指出的那样,我们可以把它们投射int
到long
之前.但是,我们必须要么
int
s,这是行不通的,因为
Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
s以某种方式希望我们永远不会Math.abs(long)
用相等的值来调用Long.MIN_VALUE
,因为我们也有Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
.我们可以BigInteger
在任何地方使用s,因为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);
}
Run Code Online (Sandbox Code Playgroud)
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));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
24665 次 |
最近记录: |