目录

1. 补码诞生的背景

2. 原码、反码、补码

2.1 原码

2.2 反码

2.3 补码

3. 加减法

3.1 普通算术加减法

3.2 模N加减法

4. 总结


1. 补码诞生的背景

不论是在生活中还是虚拟网络中,人们总是习惯与10进制数字打交道,很容易理解10进制的加减乘除运算,但是我们知道计算机无法直接理解10进制,只能识别高低电平,一般人为设定0为低电平,1为高电平,所以又称计算机是二进制的。在计算机发展早期,人们要想使用计算机,只能使用计算机看懂的二进制与计算机打交道,如穿孔纸带,人们使用穿孔纸带将程序和数据转换为二进制码,带孔为1,无孔为0,计算机读取并处理完成后,同样在纸带上以二进制打孔输出计算结果,一般人很难操作这种早期计算机,只能是专业人士才能处理二进制的转换。随着科技的进步,普通人也能熟练的操作计算机,表面上似乎计算机已经理解了10进制,但是实际上,计算机最底层还是二进制的,这就需要10进制到二进制的自动转换以及使用二进制进行各种运算。

10进制到二进制的转换需要考虑两方面,第一个是编码格式,二进制中只有0和1,不同于常用的10进制使用 + 或者 - 符号代表正负数,要想让二进制只使用1和0代表正负数,需要找到合适的编码格式;第二个是运算,以加减运算为例,计算机内部是比较复杂的,计算机实现加法运算是很容易的,若直接作减法则比较复杂,需要处理借位等等,内部逻辑组件会增多,所以计算机一般在减去一个数的时候会转成加上这个被减数的负数,将减法转换成了加法,即A - B = A + (-B)。所以需要找到一种满足这两个方面的编码,目前10进制转换成二进制主要有三种方式:原码、反码、补码,下面将从编码格式和运算两方面对比这三种编码格式。

2. 原码、反码、补码

2.1 原码

原码是最简单也是最直观的从10进制到二进制的编码格式,人为规定原码的最高位为符号位,正数为0,负数为1,其余所有位为10进制数的绝对值。如下面例子:

10进制 二进制原码(4位)
4 0 100 (首位为0,代表为正数)
2 0 010 (首位为0,代表为正数)
0 0 000 (首位为0,代表为正数)
-2 1 010 (首位为1,代表为负数)
-4 1 100 (首位为1,代表为负数)

原码的优点是编码格式对人很友好,类似十进制中的正负号,原码用最高位0和1分别代码正负数,很直观的表示了正负数。但是原码也有一个很大的缺点,就是无法将减法转换成加法运算,如:

4 - 2 (10进制)= 4 + (-2)= 0 100 + 1 010  (二进制原码) = 1110 (二进制原码)= -6 (10进制)

上面例子计算4-2,将4-2转换成4+(-2)并用原码计算,得出的结果错误,原码虽然很直观转换了10进制数,但是计算输出的原码值并不正确,所以计算机不能直接使用原码存储和计算。

2.2 反码

反码的出现,主要是为了解决原码无法执行减法运算的问题,人为规定反码最高位为符号位,正数为0,负数为1,反码正数与原码正数格式一致,反码负数为负数绝对值的原码按位分别取反,如下面例子:

10进制 二进制原码(4位) 二进制反码(4位)
4 0 100 (首位为0,代表为正数) 0 100 (首位为0,代表为正数)
2 0 010 (首位为0,代表为正数) 0 010 (首位为0,代表为正数)
0 0 000 (首位为0,代表为正数) 0 000 (首位为0,代表为正数)
-2 1 010 (首位为1,代表为负数) 1 101 (首位为1,代表为负数)
-4 1 100 (首位为1,代表为负数) 1 011 (首位为1,代表为负数)

反码的负数编码格式不像原码那样直观,但是却可以将减法转换成加法了,反码减法规则为:A - B = A + (-B),如果最高位发生了溢位,则需要在最低位加上1,如下面两个例子:

1)4 - 2 (10进制)= 4 + (-2)= 0 100 + 1 101  (二进制反码) = 1 0001 (二进制反码,发生了溢位)=  0001 + 0001(最低位加1) = 0010 (二进制反码)= 2(10进制)

2)2 - 2 (10进制)= 2 + (-2)= 0 010 + 1 101  (二进制反码) = 1111 (二进制反码)=  - 0 (10进制)

运用反码减法规则,得到的上面两个例子的减法结果是正确的,所以计算机是可以使用反码存储和计算的,早期的计算机如CDC 6000、LINC、PDP-1等都是使用反码的,但是反码也有两个缺点:1)0有两种编码,+0 (0000)和 -0 (1111),在判断0时,需要分别判断0000和1111;2)反码减法的算法规则比较复杂,需要增加计算机内部逻辑组件额外判断溢位,会影响计算效率。

2.3 补码

补码是现代计算机使用的编码格式,解决了上面反码的两个缺点。正数的补码与原码格式相同,负数的补码是将负数绝对值的原码分别按位取反,并加1,如下面例子

10进制 二进制原码(4位) 二进制补码(4位)
4 0 100 (首位为0,代表为正数) 0 100 
2 0 010 (首位为0,代表为正数) 0 010 
0 0 000 (首位为0,代表为正数) 0 000 
-2 1 010 (首位为1,代表为负数) 1 110
-4 1 100 (首位为1,代表为负数) 1 100

补码的减法规则比较简单,按照最简单的转换公式A-B = A + (-B),当减去一个数时直接转换成加上被减数的负数即可,不用像反码那样额外处理溢位,如下面两个例子:

1)4 - 2 (10进制)= 4 + (-2)= 0 100 + 1 110  (二进制补码) = 1 0010 (二进制补码,发生了溢位,直接丢弃溢位)=  0010(二进制补码) = 2(10进制)

2)2 - 2 (10进制)= 2 + (-2)= 0 010 + 1 110  (二进制补码) = 1 0000(二进制补码,发生了溢位,直接丢弃溢位)=  0000 (二进制补码) = 0(10进制)

使用了补码的加法,上面两个例子得出的结果都是正确的,相对于反码,补码加法更简单,直接丢弃溢位,不需要针对溢位单独处理,所以用补码做运算效率高。虽然补码运算过程很简单,但是转换和运算规则却很难理解,要弄明白其中的原理,就需要揭开补码背后的数学奥秘。

3. 加减法

加减运算有两种运算方式,一种是普通算术加减法,通常生活中使用的是10进制普通算术加减法;另一种是模N加减法,计算机补码执行加减运算,则是使用了模N加减法。

3.1 普通算术加减法

普通算术加减法是我们在生活中一直使用的,也是最简单和最容易理解的,通常人为使用 + 和 - 符号规定正负数,正数通常省略 + 符号, 如10,20,-10,-20,正负数的加减运算则可以看成是一维运算,如下图:

上图是普通算术加减法示意图,当执行加法运算时,需要向右移动,比如0+3,在0位置向右移动3位,即为0+3的结果;同样的,当执行减法运算,向左移动。向左和向右是没有尽头的,可以一直移动到正的无穷大或者负的无穷大。普通算术加减法简单直观,很容易被人理解,但是对于计算机要实现这样的算术加减法,既要区分正负数,又要分别实现加减法,设计就会很复杂,效率会很低,所以这套算术加减法并不适用计算机。所以需要找到一种不需要区分正负数就可以实现加减法转换的规则,那么计算机运行效率就会最高。

3.2 模N加减法

模N加减法正是不需要区分正负数就可以实现加减法转换的运算方式,不同于普通算术加减法,它是二维运算,要理解模N加减法比较困难,可以先用生活最典型的时钟举例,如下图:

上面是生活中常见的时钟,如果当前时间为凌晨1点,要知道5个小时之后的时间是多少,只需要顺时针旋转5格,指向了6点,即为1+5的结果;如果想知道5个小时之前的时间是多少,需要逆时针旋转5格,指向晚上8点,即为1-5的结果。时钟顺时针相当于时间向前走,逆时针相当于时间往后走,但是时钟不会指向无穷大的数,当转过24个小时(24小时制)又回到了原点。在时钟转动中,1-5的最终结果为晚上8点,逆时针旋转5个小时就可以得到正确结果,同时也可以顺时钟旋转19个小时(24-5,24小时制),两种方式旋转都最终指向了晚上8点。所以任意逆时针旋转得到的结果都能通过顺时钟旋转得到,当逆时针旋转N个小时,与顺时针旋转24-N小时相等,24又称为模,如果把顺时针看成是加法,逆时针看成是减法,那么时钟旋转可以看成模24的加减法运算,满足公式A-m=A+(24-m),即在时钟任一时刻A点,从A点逆时针旋转m个小时得到的结果,与从A点顺时针旋转24-m得到的结果一致。模N运算将减法转换成了加法。

计算机使用的二进制位数是有限制的,比如4位,8位,16位,64位等等,当数值太大超过最大位数时,会发生溢出,重新归0,所以计算机的二进制能表示的数不是无穷大的,由于溢出归零的特点,更像时钟旋转,如下图:

上图的四位二进制表示了从0000-1111,当超出1111时,四位已无法表示,会发生溢出,高于四位的位会被丢掉,比如1111加上2等于10001,10001包含五位二进制,最高位1会被丢掉,实际结果为0001,与时钟运算很相似,相当于在1111顺时针旋转了2个数。在时钟运算中,将顺时针看成加法,逆时针看成减法,那么时钟运算可以看成是模24的加减法,同理四位二进制也可以看成是模N的加减法,在4位二进制中,转一圈为2^4=16,所以4位二进制的加减法为模16的加减法,减法很容易的就被转换成了加法,即满足模N加减法公式:A-m=A+(16-m)。

虽然根据模N加减法实现了加减法转换,但此时又有新的问题,4位二进制只有1和0,是没有区分正负数的,而人们在计算的时候是要区分正负数的,所以需要人为将部分二进制划分为负数,另一部分划分为正数,根据模N加减法公式A-m=A+(16-m),当A为零点时,根据模N加减法公式得到 0-m=0+16-m,即-m=16-m,即将零点A逆时针移动m得到负数m,同时这个负数m也可以从零点A顺时针移动16-m得到,零点A可以为上面四位二进制任意一位,比如定义0000或者0001为零点都是可以的,但是为了简单运算,人为规定0000为零点,0000逆时针方向的为负数,顺时针方向的为正数。如在0000逆时针旋转1个数或者顺时针旋转16-1得到1111,那么1111代表-1,相应的顺时针移动一个数为+1,即用0001表示+1;同理在0000逆时针旋转2个数或者顺时针旋转16-2得到1110,那么1110代表-2,相应的顺时针移动两个数为+2,即用0010表示+2;同理1101和0011分别为-3和+3,1100和0100分别为-4和+4,1011和0101分别为-5和+5,1010和0110分别为-6和+6,1001和0111分别为-7和+7,但是1000比较特殊,0000逆时针旋转8个数得到1000,所以1000为-8,相应的顺时针旋转8个数也得到了1000,1000既能表示-8又能表示+8,为了不产生冲突,人为规定1000为-8。如下图:

上图中的四位二进制根据模N加减法划分出了正负数,同理对任意n位二进制,模N等于=2^n,根据上面的模N加减法公式得到-m = N - m = 2^n - m = (2^n -1) - m + 1,最终得到了负数推导公式-m = (2^n -1) - m + 1,(2^n-1)-m即为负数的原码绝对值按位取反,之后再加上1可以快速得到负数编码,又称这种负数编码为补码。补码负数范围转换成10进制为 -1 ~ -2^(n-1),正数范围转换成10进制为 0 ~ 2^(n-1)-1,所以补码转换成10进制为 -2^(n-1) ~ 2^(n-1)-1。

4. 总结

要想弄清楚补码,必须要弄清楚补码要解决的问题,计算机是二进制的,无法直接表示正负数,另外在计算机内部直接实现减法,也会影响计算机效率,所以人们希望要找到一种既能使用二进制表示10进制正负数的编码格式,同时这种编码格式又能满足将减法转换成加法进行运算,同时满足这两个条件有反码和补码,但由于反码中的0有两个编码格式,另外反码加法运算也比较复杂,慢慢地反码被淘汰了。补码刚好解决了反码的两个缺点,所以补码成了现代计算机的通用编码。

补码加减法运算不同于常规的算术加减法,补码使用了模N加减法,要想完全理解补码,首先要理解模N加减法。

计算机为什么要用补码相关推荐

  1. 计算机为什么要用补码?

    人类在制造出晶体管后,利用晶体管制造出了与非门,然后又利用与非门制造出了加法器.加法器解决了加法运算问题.只有加法器是不够的,还需要解决减法的计算问题,但是与加法器相比,设计减法器硬件更为复杂,增加了 ...

  2. 验证:数据在计算机内存中以补码形式存储

    #include<stdio.h> int main() {unsigned int a = -10;printf("%u", a); } 这个程序的输出是什么? 我们 ...

  3. 为什么计算机当中要采用补码

    为什么用补码: (1) 为什么计算机中要使用补码? 在计算机的8位二进制表示法中,有原码.反码.补码三种方法.最高位均表示符号位,0+1-. 1.原码 正数 0 XXXXXXX 负数 1 XXXXXX ...

  4. 计算机中原码反码补码的应用场合,反码

    反码是数值存储的一种,多应用于系统环境设置,如linux平台的目录和文件的默认权限的设置umask,就是使用反码原理.在计算机内,定点数有3种表示法:原码.反码和补码. 中文名 反码 外文名 Inve ...

  5. 源码 反码 补码详解(为什么计算机存储数值为补码形式?)

    一. 机器数和真值 在学习原码, 反码和补码之前, 需要先了解机器数和真值的概念. 1.机器数 一个数在计算机中的二进制表示形式,  叫做这个数的机器数.机器数是带符号的,在计算机用一个数的最高位存放 ...

  6. 深入理解计算机底层为什么采用补码运算【如何理解二进制计算高位溢出】

    在计算机底层运算设计的过程中,是根据现实生活中的数学运算做出的映射.比如数学中的8-3=8+(-3),那么这样一来减法运算就变成了加法运算(你这时可能会问,我脑子直接计算8-3=5了,何必再转换位成加 ...

  7. 原码、补数、补码以及计算机中为什么用补码存储

    原码:最左侧一位表示符号,且0表示正数,1表示负数:二进制转换为十进制时,符号位只用于取正负号,不参与转化. 例如1个字节的二进制: 0000 0001表示十进制的1: 0000 1010表示十进制的 ...

  8. java部分基础知识 (二):计算机组成原理 原码 补码 反码 按位符 移位符 按位与 按位或 按位抑或 非 分析hashMap的put方法原理

    这里写目录标题 引言 符号位 正数的二进制计算 负数的二进制计算 按位符和移位符 按位符 移位符 分析hashMap运算符 byte和char 总结 引言 最近做完一个项目后,我忽然发现自己的基础并不 ...

  9. 计算机组成原理真值的补码,计算机组成原理:真值,原码,补码,反码,移码...

    一,真值 就是现实中的数字(二进制)必须有+/-,实际中整数舍弃了+. eg:+1101010001 -1010001111 二,原码 计算机中唯一标识一个真值,但是不能用于计算以及无法实现减法,会产 ...

  10. 计算机组成原理:原码,补码,反码,移码

    无符号数 寄存器的位数反映和决定无符号数的表示范围 比如八位的寄存器就只能储存十进制的0-255 有符号数 机器数与真值 在计算机当中没有硬件表示小数点的位置,而小数点的位置是我们自己约定的, 小数的 ...

最新文章

  1. 如何在全局程序集缓存 (GAC) 中安装 DLL 文件
  2. 在拦截器中获取请求参数,[Ljava.lang.String; cannot be cast to java.lang.String报错
  3. nginx反向代理编译异常
  4. kubernetes集群配置dns服务
  5. Universal-imageLoader缓存图片加载
  6. Android 使用Adapter适配器模式实现无线轮播BannerView
  7. 容器源码解析之HashMap(七)
  8. php运用like乱码,使用MySql和php出现中文乱码的解决方法
  9. 计算机网络7种类型,OSPF中7种类型LSA
  10. day18-事务与连接池 1.复习
  11. 2022年高压电工考试模拟100题及在线模拟考试
  12. 生成对抗网络GANs的用途
  13. C++ SHFileOperation实现文件、文件夹拷贝、删除、重命名
  14. 文本表示与文本特征提取的区别
  15. 敌兵布阵 HDU - 1166(树状数组-模板线段树写法)
  16. go语言能开发什么?go语言开发案例
  17. 计算机亮度快捷键,调节电脑亮度的快捷键是什么
  18. 使用清华镜像站下包、pip通过清华镜像站下载
  19. 减少代码重复率的方法
  20. VLAN特性 聚合、MUX VLAN、QinQ、映射

热门文章

  1. 如何用mysql创建股票数据库_mysql数据库创建表
  2. Libratone小鸟音响发布TRACK Air真无线系列耳机
  3. c语言编译器怎窗口怎么执行,c语言编译(c语言编译执行详解)
  4. PageOffice使用实例
  5. 真无线蓝牙耳机品牌排行榜, 四款国产良心蓝牙耳机
  6. mysql 查询练习
  7. nfc 蓝牙快速配对 android,索尼WF-SP900耳机怎么通过NFC连接
  8. SpringBoot+Redis哨兵模式
  9. String.java中contains方法
  10. 一文带你读懂数字管家