[Java]补码与移位操作

对补码一直存在疑惑,查了好些资料算是略知一二,简单总结一下。

原码、反码与补码

Java中整型都是带符号的,int是【首位符号位+31位数字】,short是【首位符号位+15位数字】,byte是【首位符号位+7位数字】。
为了偷懒,以下皆以8位的byte为例。

原码

  • 正数首位为0
    0 ~ 0000 0000
    1 ~ 0000 0001
    2 ~ 0000 0010

    31 ~ 0111 1111
  • 负数首位为1
    -32 ~ 1000 0000
    -1 ~ 1000 0001

    -31 ~ 1111 1111
  • 除了将1000 0000(负0)表示-32,负数就是正数编码首位置1,其他没啥好讲的。

反码

  • 正数反码就是本身
  • 负数反码为原码按位取反(翻转)
    反码也没啥,容易理解。

补码

  • 正数补码就是本身
  • 负数补码为其反码+1
    补码其实用到了同余的概念,负数 -x % 64 = (-x+64) % 64,这样就把减法转换为了加法:
    a - x = a + ( -x ) = a + ( 64 - x ) //有可能会溢出,但舍弃溢出位之后,结果是正确的
    至于为什么负数补码为其反码+1,可以当成是个巧合。
  • 试着解释下
    64 ~ [1] 0000 0000 ,可看作带溢出位的0。
    -x + 64 = (-x + 63) + 1,前半部分相当于按位取反,首位符号位1+1溢出舍弃。
    例如:-12(1000 1100)补码为 0111 0100,转为10进制是20;
    -12+64=52,去掉溢出位(-32)是20,结果相同。
    得出-x的补码为其反码+1。
  • 为什么要+1
    我的理解是,问题出在编码上。如果1000 0000表示负0而不是-32,则不需要+1。但这样的话byte仅能表示63个数而不是64个数,估计当初设计者有所考量,就做了这么一个改动。
    改完之后相当于把负半轴整体左移1个单位,所以取反码加1才能完全覆盖正半轴。

减法计算过程

例:1 -30
0000 0001 + (1110 1010)[^取反码]=0000 0001 + 0001 0110 =0001 0111
反码转回原码,是减一取反,为1110 1001 ,即-29。

移位操作

<<和>>是带符号的移位,左移相当于乘以2,右移相当于除以2(舍弃小数位),这两个都会保留符号位。
负数移位存在【取绝对值>>取反码>>移位>>转回原码】操作,最后将首位置为1。
所以-1>>1=-1 (不是0也不是负0:-2147483648)。
需要注意的是,溢出之后移位结果将会出错,需要特别当心。

“>>>” 是无符号的右移,负数移动后就也变成正数了,所以如果负数这么移位,要乘以-1才正确。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值