java原码 反码 补码解释

起因:

今天碰到这样一道题目,求a的b次方。思路很简单,就是用快速幂。

但是测试用例中有这样一个:a=2, b=-2147483648. 

 

代码中我直接用了Math.abs()取了绝对值,这个用例就过不去。看了源码:

     /**
     * Returns the absolute value of an {@code int} value.
     * If the argument is not negative, the argument is returned.
     * If the argument is negative, the negation of the argument is returned.
     *
     * <p>Note that if the argument is equal to the value of
     * {@link Integer#MIN_VALUE}, the most negative representable
     * {@code int} value, the result is that same value, which is
     * negative.
     *
     * @param   a   the argument whose absolute value is to be determined
     * @return  the absolute value of the argument.
     */
    public static int abs(int a) {
        return (a < 0) ? -a : a;
    }

abs对Integer.MIN_VALUE返回的还是它自己,并且使用的就是"-"来取相反数。也就是说对于-2147483648取反还是-2147483648。所以我的代码错了。当然,特殊处理这个值代码就能过,可是我想知道为什么。

经过一番考虑,得出结论是这样的:

32位太长了,此处以8位为例。

先看一下,为什么8位整数表示 -128~127,主要考虑这个-128哪里来的

原码:
 0 000 0000    +0
 ...
 0 111 1111    +127

 1 000 0000    -0
 1 000 0001    -1
 ...
 1 111 1111    -127

反码:
 0 000 0000    +0
 ...
 0 111 1111    +127

 1 111 1111    -0
 1 111 1110    -1
 ...
 1 000 0000    -127

补码:
 0 000 0000    +0
 ...
 0 111 1111    +127

10 000 0000    -0    //-0求补码之后 舍弃超出的位和+0是一样的
 1 111 1111    -1
 ...
 1 000 0001    -127
 1 000 0000    -128    //因为-0重叠了 少了一个数1 000 0000刚好就拿来作为-128

两个问题:

补码加减:

我们知道计算机之所以转换成补码,是因为补码可以连带着符号位直接二进制加减,非常方便。

来看-128 + 1和-128 - 1的效果:

-128 + 1:
  1 000 0000
+ 0 000 0001
= 1 000 0001 = -127
注意这里都是补码运算,因为是计算机算的嘛

-128 - 1:
  1 000 0000
- 0 000 0001
= 0 111 1111 = 127

  1 000 0000
+ 1 111 1111
=10 111 1111 = 127 舍弃超出的位

可以看到 -128-1超出了8位能表示的范围下一位就是最大值127
不管直接-1还是+(-1)都是一样的结果

同样的道理 127 + 1 = -128。 这也就是和时钟的圈圈一个道理,形成了一个环。所以写算法的时候,需要考虑到这种边界情况。

用“-”取相反数:

127取相反数-127:
0 111 1111 对它进行-操作相当于下面两步
0 000 0001 求补
1 000 0001 符号位取反
结果等于 -127

-127取相反数-(-127):
1 000 0001 对它进行-操作相当于下面两步
1 111 1111 求补
0 111 1111 符号位取反
结果等于 127

所以结论就是:
-操作 等价于 求补然后符号位取反
其实逻辑也是这样 补码再求补就是原码 然后符号位取反就等于相反数 没毛病

-128取相反数-(-128):
 1 000 0000
10 000 0000 求补 舍弃超出的位
 1 000 0000 符号位取反
结果等于 -128

上面的解释说的很清楚了。

结论:

Integer.MAX_VALUE + 1 = Integer.MIN_VALLUE

Integer.MIN_VALLUE - 1 = Integer.MAX_VALUE

-Integer.MIN_VALLUE = Integer.MIN_VALLUE

abs(Integer.MIN_VALLUE) = Integer.MIN_VALLUE

在写算法的时候,如果题目就是明确要求涉及到了这些边界的加减求相反数这些操作,就要特殊考虑了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值