计算机基础之原码、反码、补码

本文介绍了原码、反码、补码的概念,通过时钟例子解释补码原理。以二进制运算展示,仅用原码计算减法结果错误,而用补码可正确运算。指出反码、补码存在是为让负数参与加法运算,补码等于反码加1是为使原码与补码和为周期数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相信大家应该或多或少的都了解过原码、反码、补码吧。

原码:原码就是早期用来表示数字的一种方式: 一个正数,转换为二进制位就是这个正数的原码。负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码。

反码:正数的反码就是原码,负数的反码等于原码除符号位以外所有的位取反。

补码:正数的补码与原码相同,负数的补码为 其原码除符号位外所有位取反(得到反码了),然后最低位加1。

————————————————————————————————————————————————————————

这些理解起来并不难,但是,大家有没有想过,已经有原码了,为什么要有反码、补码这两个东西?再一个,为什么补码是反码+1运算得到的?

给大家举个例子。

一个时钟,如果要从9点走到4点,需要怎么走?

第一种可以逆时针往回走5个小时,第二种可以接着顺时针走7个小时。

这个结果大家数数手指头就能算出来,但其实,也可以用表达式计算出来。

首先,我们要知道,时钟的周期是12个小时,每超过12小时,就会归零。那么,顺时针走的话,分两个阶段,一个是走3个小时到12点,这个时候就已经需要重置了,然后在走4个小时,就到了4点这个时刻。

我们可以姑且把3认为是9的补码,因为9 + 3 = 12,而12就是时钟的周期。

现在,我们可以把表达式给计算出来,

4 + (12 - 9)------> 目标时间 + (周期 - 起始时间)

比如11点到9点

第一种是直接11 + (-9) = 2,逆时针往回走2小时,

第二种是9 + (12 - 11) = 10,顺时针再走10个小时。

————————————————————————————————————————————————————————

现在,我们再来看看二进制中负数的反码和补码(因为正数的反码、补码都是本身,所以没必要看)。

比如 -5,首先我们不考虑符号位,-5的绝对值是5,5的二进制是 0 1 0 1,然后将0 1 0 1逐位取反得到 1 0 1 0,

现在我们用 0 1 0 1 + 1 0 1 0  = 1 1 1 1,1 1 1 1 转成十进制就是15,而15 + 1就是4位二进制的周期16,

所以我们需要再反码的基础上+1,才能得到周期数,也就是说反码+1,就是补码。

————————————————————————————————————————————————————————

下面我们再来看下,为什么需要补码,这个东西。

我们要知道,计算机只认识二进制,也根本不认识加减乘除运算,他能做的,只有与、或、异或、取反、左移、右移这几种运算,不熟悉的可以看我的这篇文章https://blog.youkuaiyun.com/qq_32069155/article/details/92441430

首先,我们来看下9 - 5在计算机中是怎样运算的。

假设我们没有反码、补码,只有原码。那么我们先直接用9的二进制位0 0 0 0 1 0 0 1  加上 -5的二进制位 1 0 0 0 0 1 0 1看看能不能得到结果。

      0 0 0 0 1 0 0 1 

      1 0 0 0 0 1 0 1   

异或-------------------- 

      1 0 0 0 1 1 1 0

      0 0 0 0 1 0 0 1 

      1 0 0 0 0 1 0 1

  与-------------------- 

      0 0 0 0 0 0 0 1

发现存在进位,则将与运算结果左移一位,得到 0 0 0 0 0 0 1 0,然后将上次异或结果和左移结果再进行异或运算

      1 0 0 0 1 1 1 0

      0 0 0 0 0 0 1 0

异或-------------------- 

      1 0 0 0 1 1 0 0

      1 0 0 0 1 1 1 0

      0 0 0 0 0 0 1 0

  与-------------------- 

      0 0 0 0 0 0 1 0

发现存在进位,则将与运算结果左移一位,得到 0 0 0 0 0 1 0 0,然后将上次异或结果和左移结果再进行异或运算

      1 0 0 0 1 1 0 0

      0 0 0 0 0 1 0 0

异或-------------------- 

      1 0 0 0 1 0 0 0

      1 0 0 0 1 1 0 0

      0 0 0 0 0 1 0 0

  与-------------------- 

      0 0 0 0 0 1 0 0

发现存在进位,则将与运算结果左移一位,得到 0 0 0 0 1 0 0 0,然后将上次异或结果和左移结果再进行异或运算

      1 0 0 0 1 0 0 0

      0 0 0 0 1 0 0 0

异或-------------------- 

      1 0 0 0 0 0 0 0

      1 0 0 0 1 0 0 0

      0 0 0 0 1 0 0 0

  与-------------------- 

      0 0 0 0 1 0 0 0

发现存在进位,则将与运算结果左移一位,得到 0 0 0 1 0 0 0 0,然后将上次异或结果和左移结果再进行异或运算

      1 0 0 0 0 0 0 0

      0 0 0 1 0 0 0 0

异或-------------------- 

      1 0 0 1 0 0 0 0

      1 0 0 0 0 0 0 0

      0 0 0 1 0 0 0 0

  与-------------------- 

      0 0 0 0 0 0 0 0

发现不存在进位,则上次异或结果 1 0 0 1 0 0 0 0就是最终结果,也就是 -16。

是不是发现,跟直接9 - 5 的结果完全不一样?也就是说计算机不能直接加上负数的原码,也就是时钟问题中,不能直接减去多少小时,来达到目的时间。那么,在时钟问题中,除了直接减,还有一种加上补码的方式去计算,我们可以来试下。

还是9 - 5,现在我们用9的二进制 0 0 0 0 1 0 0 1 加上-5 的补码 1 1 1 1 1 0 1 1

      0 0 0 0 1 0 0 1

      1 1 1 1 1 0 1 1

异或-------------------- 

      1 1 1 1 0 0 1 0

      0 0 0 0 1 0 0 1

      1 1 1 1 1 0 1 1

  与-------------------- 

      0 0 0 0 1 0 0 1

发现存在进位,则将与运算结果左移一位,得到 0 0 0 1 0 0 1 0,然后将上次异或结果和左移结果再进行异或运算

      1 1 1 1 0 0 1 0

      0 0 0 1 0 0 1 0

异或-------------------- 

      1 1 1 0 0 0 0 0

      1 1 1 1 0 0 1 0

      0 0 0 1 0 0 1 0

  与-------------------- 

      0 0 0 1 0 0 1 0

发现存在进位,则将与运算结果左移一位,得到 0 0 1 0 0 1 0 0,然后将上次异或结果和左移结果再进行异或运算

      1 1 1 0 0 0 0 0

      0 0 1 0 0 1 0 0

异或-------------------- 

      1 1 0 0 0 1 0 0

      1 1 1 0 0 0 0 0

      0 0 1 0 0 1 0 0

  与-------------------- 

      0 0 1 0 0 0 0 0

发现存在进位,则将与运算结果左移一位,得到 0 1 0 0 0 0 0 0,然后将上次异或结果和左移结果再进行异或运算

      1 1 0 0 0 1 0 0

      0 1 0 0 0 0 0 0

异或-------------------- 

      1 0 0 0 0 1 0 0

      1 1 0 0 0 1 0 0

      0 1 0 0 0 0 0 0

  与-------------------- 

      0 1 0 0 0 0 0 0

发现存在进位,则将与运算结果左移一位,得到 1 0 0 0 0 0 0 0,然后将上次异或结果和左移结果再进行异或运算

      1 0 0 0 0 1 0 0

      1 0 0 0 0 0 0 0

异或-------------------- 

      0 0 0 0 0 1 0 0

      1 0 0 0 0 1 0 0

      1 0 0 0 0 0 0 0

  与-------------------- 

      1 0 0 0 0 0 0 0

发现存在进位,则将与运算结果左移一位,得到 0 0 0 0 0 0 0 0,然后将上次异或结果和左移结果再进行异或运算

      0 0 0 0 0 1 0 0

      0 0 0 0 0 0 0 0

异或-------------------- 

      0 0 0 0 0 1 0 0

      0 0 0 0 0 1 0 0

      0 0 0 0 0 0 0 0

  与-------------------- 

      0 0 0 0 0 0 0 0

发现不存在进位,则上次异或结果 0 0 0 0 0 1 0 0就是最终结果,也就是 4。

所以,可以得出结论,计算机可以直接加上其被减数的补码,来达到运算减法的问题,也就是说,补码,其实就是为了更方便的减法运算,他可以使得负数能够使用加法器参与加法运算。

总结下:反码、补码之所以存在是为了是负数能直接参与加法运算,计算机只用实现加法,就能达到实现加减乘除。

补码 = 反码 + 1是因为原码 + 反码  = 1 1 1 1,也就是当前容量的最大数,但是,只有再加一,才会等于周期数,然后我们上面了解到,补码加上原码会等于周期数,所以补码 = 反码 + 1。

自此,本文结束,上述内容是参考了https://blog.youkuaiyun.com/zhuozuozhi/article/details/80896838之后,本人所做的一些总结和补充,如果什么不足,还请指正。

PS:本文中,还有一个坑,大家可以找找看。 = =。

 

 

### 原码反码补码的定义 #### 1. 原码 (Sign-Magnitude Representation) 原码是一种最简单的机器数表示方法。最高位为符号位,“0”代表正数,“1”代表负数;其余各位则按二进制绝对值的形式来表示数值。 例如,8位二进制中的`0000 0001`表示+1,而`1000 0001`表示−1[^1]。 #### 2. 反码 (One's Complement) 对于正数而言,其反码与其原码相同。而对于负数来说,则需先求得该数对应的正数部分的原码,再将每一位取反(即0变1,1变0),得到的结果就是这个负数的反码。 比如,在8位系统里,`-7`的原码是`1000 0111`,那么它的反码则是`1111 1000`[^3]。 #### 3. 补码 (Two's Complement) 同样地,当涉及到正值时,补码等于原码。但对于负值情况有所不同:首先获取对应正数的原码,接着对其逐位取反获得反码之后再加上1即可得出最终结果——这就是所谓的“加一法则”。 举例说明,仍以8位为例,如果要表达`-5`的话: - 正五的原码:`0000 0101` - 对应的反码:`1111 1010`(每位都翻转) - 加上1后的补码:`1111 1011` 因此,`-5`在八位下的补码形式就应该是`1111 1011`[^2]。 ### 计算实例展示 假设现在有一个十进制整数 `-14` 需要用到七位加上一位符号位共八个比特位来进行编码: - **原码**: `1000 1110` (其中首位'1'作为符号标记) - **反码**: 将上述除开首字符外的所有数字反转得到 `1111 0001`. - **补码**: 继续给上面所得出的数据加1变成 `1111 0010`. 值得注意的是,实际应用中几乎总是采用补码而非其他两种方式存储数据,因为这可以简化硬件设计并提高效率[^4]. ```python def to_binary(n, bits=8): """Convert an integer n into a binary string with specified number of bits.""" return format(n if n >= 0 else (1 << bits) + n, '0{}b'.format(bits)) print(to_binary(-14)) # Output should be the two's complement representation of -14 using default bit length. ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值