文章目录

  • 1. 补码诞生的背景
  • 2. 原码、反码、补码
    • 2.1 原码
    • 2.2 反码
    • 2.3 补码
  • 3. 加减法
    • 3.1 普通算术加减法
    • 3.2 模N加减法

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进制数的绝对值。如下面例子:

原码的优点是编码格式对人很友好,类似十进制中的正负号,原码用最高位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,反码正数与原码正数格式一致,反码负数为负数绝对值的原码按位分别取反,如下面例子:

反码的负数编码格式不像原码那样直观,但是却可以将减法转换成加法了,反码减法规则为: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,如下面例子


补码的减法规则比较简单,按照最简单的转换公式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加减法。

2020-10-27(原码,反码,补码的产生)相关推荐

  1. 10.原码 反码 补码

    +7的原码:0000 0111 -7的原码:1000 0111   第一位0代表正数,1代表负数,第一位为符号位 +7的反码:0000 0111 正数反码和原码一样 -7的反码:1111 1000   ...

  2. C语言基础(二)—— 常量与变量、数据类型、进位制、关键字、原码反码补码、限定符、字符串格式化输入输出

    1. 常量与变量 1.1 关键字 1.2 数据类型 数据类型的作用:编译器预算对象(变量)分配的内存空间大小. 1.3 常量 在程序运行过程中,其值不能被改变的量 常量一般出现在表达式或赋值语句中 整 ...

  3. 由Python位运算到原码反码补码

    采用书籍Python核心编程(第二版),人民邮电出版社,2008年7月第1版.本书以Python2.5为主,但笔记主要以Python3.6为主. 一.Python位运算操作符 Python支持标准位运 ...

  4. 关于计算机中 原码, 反码, 补码 详解

    本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希 ...

  5. 原码, 反码, 补码, 移码 详解

    本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希 ...

  6. 原码 反码 补码 详解

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

  7. python二进制反码例题_python中的进制转换和原码,反码,补码

    python中的进制转换和原码,反码,补码 计算机文件大小单位 b = bit 位(比特) B = Byte 字节 1Byte = 8 bit #一个字节等于8位 可以简写成 1B = 8b 1KB ...

  8. 原码 反码 补码 详解

    本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希 ...

  9. 数制和码制(数制的转换的方法,BCD码<8421,2421,5421,余三码>,格雷码,原码,反码,补码,定点数和浮点数)

    目录 1.数制的转换 1)二,八,十六进制进制转十进制 加权系数求和法 2)十进制转二,八,十六进制 除基取余法(短除法) 减权定位法 3)二,八,十六进制的相互转换 2.BCD码 3.格雷码 4.原 ...

  10. Debug和release版本区别 原码反码补码的转换及存储

    #define _CRT_SECURE_NO_WARNINGS 1  //Debug和release版本区别(VS2019版) //例子 #include<stdio.h> //int m ...

最新文章

  1. ThoughtWorks雷达上的新奇变化
  2. ORB-SLAM3 Initializer.cpp函数解读
  3. 坦白讲!90%的数据分析师都不合格!!
  4. SpringBoot 配置错误页
  5. Typecho双栏博客免费主题—Splity
  6. 关于java中实现在oracle数据库中实现对中文首字母进行排序的解决方案
  7. 线程之间的通信(thread signal)
  8. linux ll命令时间,linux ll显示时间格式
  9. Keil MDK下载程序时的相关设置
  10. 用VMWARE学习组网(二)
  11. 定了!这 35 所高校将设人工智能本科专业!
  12. 通信原理(第七版)常见公式
  13. linux压力测试脚本,一种基于shell脚本的CPU压力测试方法与流程
  14. c语言傅立叶变换,傅立叶变换与傅立叶反变换的C语言实现
  15. 如何在Web页面里使用高拍仪扫描上传图像
  16. 常用的网站建设程序有哪些?
  17. 科普一下SM系列国密算法(从零开始学区块链)
  18. LORA无线模块使用
  19. 06_XML的写入_dom4j添加、删除、修改Xml文件内容
  20. 对校招生培养工作的建议_对我校招生工作的一些粗浅想法(精)

热门文章

  1. Python之 sklearn:sklearn.preprocessing中的StandardScaler函数的简介及使用方法之详细攻略
  2. Sklearn:sklearn.preprocessing之StandardScaler 的transform()函数和fit_transform()函数清晰讲解及其案例应用
  3. 成功解决AttributeError: module tensorflow has no attribute reset_default_graph
  4. TF版本升级问题:成功解决AttributeError: module tensorflow has no attribute mul
  5. ModelFileType:XML、Hdf5、dat等不同模型文件后缀文件的简介、使用方法之详细攻略
  6. 成功解决object at 0x000002463192BAC8
  7. DL:LinearNN(numpy自定义的) solve XOR problem
  8. Crawler之Scrapy:Scrapy简介、安装、使用方法之详细攻略
  9. PHPsession工作机制以及销毁session
  10. datanode无法启动问题