昨天遇到1个问题,在java中对int数据取反,然后发现如果int是-(2的31次方),取反后还是它本身,然后使用 Math.abs()方法测试一下,也是一样的,查看了一下Math.abs() 就是一个简单的3目运算符
public static int abs(int a) {
return (a < 0) ? -a : a;
}
为此去研究了一下取反的原理,以下为个人推测,目前测试结果还是正确的,有不足之处欢迎补充.
我们都知道,计算机存储的是补码(对补码不清楚的可以看我另一篇文章),根据查到的资料,取反应该是按位取反,再加1,我这边是把符号位也一起取反了,用java代码实现如下:
public int negation(int x){
return ~x + 1;
}
然后测试了几个数据
x:-2147483648,返回:-2147483648
x:-2147483647,返回:2147483647
x:2147483647,返回:-2147483647
x:-1,返回:1
x:0,返回:0
x:1,返回:-1
和单纯的-x的效果是一样的
那么接下来我们来分析一下为什么-2147483648(也就是-(2的31次方))取反后还是它本身,int是32位,重点看头4位和尾4位
-2147483648的补码:1000 0000 0000 0000 0000 0000 0000 0000
连符号位一起取反:0111 1111 1111 1111 1111 1111 1111 1111
+1:1000 0000 0000 0000 0000 0000 0000 0000
果然还是它本身
这时候会怀疑会不会是上面的分析有问题呢?
下面验证几个特殊的数据
0的补码:0000 0000 0000 0000 0000 0000 0000 0000
取反:1111 1111 1111 1111 1111 1111 1111 1111
+1:0000 0000 0000 0000 0000 0000 0000 0000
1的补码:0000 0000 0000 0000 0000 0000 0000 0001
取反:1111 1111 1111 1111 1111 1111 1111 1110
+1:1111 1111 1111 1111 1111 1111 1111 1111
-1的补码:1111 1111 1111 1111 1111 1111 1111 1111
取反:0000 0000 0000 0000 0000 0000 0000 0000
+1:0000 0000 0000 0000 0000 0000 0000 0001
2147483647的补码:0111 1111 1111 1111 1111 1111 1111 1111
取反:1000 0000 0000 0000 0000 0000 0000 0000
+1:1000 0000 0000 0000 0000 0000 0000 0001
-2147483647的补码:1000 0000 0000 0000 0000 0000 0000 0001
取反:0111 1111 1111 1111 1111 1111 1111 1110
+1:0111 1111 1111 1111 1111 1111 1111 1111
上面几个数都没有问题,-2147483648确实是边界问题,相信long也有一样的问题
l:-9223372036854775808,-l返回:-9223372036854775808
l:-9223372036854775808,Math.abs(l)返回:-9223372036854775808
经过验证,确实如此.