原码, 反码, 补码 详解

    |     2016年3月11日   |   Java 语法基础   |     0 条评论   |    2378

计算机里一个整数可以用原码、反码、补码三种方式编码。搞清楚它们怎么算、机器为什么最终用补码,以及为什么补码加法能完成原码减法,对理解底层运算很有帮助。

一、机器数和真值

一个数在计算机中的二进制表示叫做机器数。机器数带符号:最高位存放符号,正数为 0,负数为 1。字长 8 位时,+3 是 00000011,-3 是 10000011,这两个就是机器数。

因为第一位是符号位,机器数的形式值不等于真正的数值。例如有符号数 10000011,最高位 1 代表负,真值是 -3,而不是把整串当成无符号数得到的 131。带符号位的机器数对应的真正数值,叫做机器数的真值:0000 0001 的真值 = +1,1000 0001 的真值 = -1。

二、原码、反码、补码

原码、反码、补码是机器存储一个具体数字的编码方式。

编码 正数 负数 例子(-1)
原码 符号位 + 绝对值 符号位 1 + 绝对值 1000 0001
反码 等于原码 符号位不变,其余取反 1111 1110
补码 等于原码 反码末位 +1 1111 1111

8 位原码的取值范围是 [1111 1111, 0111 1111],即 [-127, 127]。原码最贴近人脑;负数的反码、补码通常要先转回原码才能看出数值。

三、为何机器用补码

正数三种编码相同,不必多解释。负数则完全不同。人脑看见符号位就知道该加还是该减,但让计算机辨别符号位会让电路复杂。减法可以改成「加上一个负数」:1 – 1 = 1 + (-1)。如果符号位也参与运算,机器就可以只做加法。

用原码算 1 – 1:

[00000001]原 + [10000001]原 = [10000010]原 = -2   // 错

用反码:真值部分对了,却得到 -0,并且 0 有 [0000 0000] 和 [1000 0000] 两个编码。补码解决 0 的符号问题:

[0000 0001]补 + [1111 1111]补 = [0000 0000]补
(-1) + (-127) = [1111 1111]补 + [1000 0001]补 = [1000 0000]补  // -128

[1000 0000]补 表示 -128,它没有对应的原码和反码。因此 8 位原码/反码范围是 [-127, +127],补码是 [-128, 127]。32 位 int 用补码时范围为 [-2^31, 2^31-1]。

四、怎么求补码,以及 ~6 为什么是 -7

正数的原码、反码、补码都是它本身。负数 -15 的计算:

原码:1 0001111
反码:1 1110000   // 符号位不变,其余取反
补码:1 1110001   // 反码末位 +1

Java 中 int 是 4 字节。6 在机器里是 0000…0110,按位取反 ~6 得到 1111…1001。最高位为 1,这是补码表示的负数。还原原码:符号位不变、其余取反得 1000…0110,再末位加 1 得 1000…0111,即 -7。

原文出处:原码, 反码, 补码 详解

一句话总结:机器只用补码做加减,这样 0 只有一种编码,还能多表示一个最小值;~n 等于 -(n+1)。

转载请注明来源:原码, 反码, 补码 详解
本文链接地址:https://ai.zhousir.top/?p=1462
回复 取消