原码、反码、补码

在学习C语言的过程中,有遇到补码这个问题,当时感觉懂了,有貌似不是很懂;然后查了一些文档,整理了一番,以后忘记了可以再翻开这篇文档,查漏补缺吧!

原码

原码是指一个二进制数左边加上符号位后所得到的码,且当二进制数大于0时,符号位为0;二进制数小于0时,符号位为1;二进制数等于0时,符号位可以为0或1(+0/-0)。上面是维基百科的解释,也就是说二进制的第一位只表示正负,正为0,负为1,8位表示的数值范围 [-127,127];

具体如下:

# +10的源码
0 0 0 0 1 0 1 0 # -10的源码
1 0 0 0 1 0 1 0

源码显而易见的优点是数值简单直观; 缺点是不能直接参与运算 ,例如+10 + (-10) = 0,换成二进制则变成了00001010 + 10001010 = 10010100 = -20显然是错的,所以原码的符号位不能直接参与运算,如果和其他位分开,这就增加了硬件的开销和复杂性;

反码

反码是一种在计算机中数的机器码表示。对于单个数值(二进制的0和1)而言,对其进行取反操作就是将0变为1,1变为0。

正数的反码等于其原码,而负数的反码则可以通过保留其符号位,将原码的数值位取反得到。

# +10的反码
0 0 0 0 1 0 1 0 # -10的反码
1 1 1 1 0 1 0 1

补码

正数和0的补码就是该数字本身。负数的补码则是将其对应正数按位取反再加1

为什么用补码?

  首先,要明确一点。计算机内部用什么方式表示负数,其实是无所谓的。只要能够保持一一对应的关系,就可以用任意方式表示负数。所以,既然可以任意选择,那么理应选择一种最方便的方式。

补码就是最方便的方式。它的便利体现在,所有的加法运算可以使用同一种电路完成。

还是以-8作为例子。假定有两种表示方法。一种是直觉表示法,即10001000;另一种是补码表示法,即11111000。请问哪一种表示法在加法运算中更方便?随便写一个计算式,16 + (-8) = ?

16的二进制表示是 00010000,所以用直觉表示法,加法就要写成:

  0 0 0 1 0 0 0 0
+ 1 0 0 0 1 0 0 0
-----------------
1 0 0 1 1 0 0 0

可以看到,如果按照正常的加法规则,就会得到10011000的结果,转成十进制就是-24。显然,这是错误的答案。也就是说,在这种情况下,正常的加法规则不适用于正数与负数的加法,因此必须制定两套运算规则,一套用于正数加正数,还有一套用于正数加负数。从电路上说,就是必须为加法运算做两种电路。

现在,再来看补码表示法

  0 0 0 1 0 0 0 0
+ 1 1 1 1 1 0 0 0
-----------------
1 0 0 0 0 1 0 0 0

可以看到,按照正常的加法规则,得到的结果是100001000。注意,这是一个9位的二进制数。我们已经假定这是一台8位机,因此最高的第9位是一个溢出位,会被自动舍去。所以,结果就变成了00001000,转成十进制正好是8,也就是16 + (-8) 的正确答案。这说明了,2的补码表示法可以将加法运算规则,扩展到整个整数集,从而用一套电路就可以实现全部整数的加法。

补码的本质

在回答2的补码为什么能正确实现加法运算之前,我们先看看它的本质,也就是那两个步骤的转换方法是怎么来的。要将正数转成对应的负数,其实只要用0减去这个数就可以了。比如,-8其实就是0-8。

已知8的二进制是00001000,-8就可以用下面的式子求出:

  0 0 0 0 0 0 0 0
- 0 0 0 0 1 0 0 0

因为00000000(被减数)小于0000100(减数),所以不够减。请回忆一下小学算术,如果被减数的某一位小于减数,我们怎么办?很简单,问上一位借1就可以了。所以,0000000也问上一位借了1,也就是说,被减数其实是100000000,算式也就改写成:

1 0 0 0 0 0 0 0 0
- 0 0 0 0 1 0 0 0
-----------------
1 1 1 1 1 0 0 0

进一步观察,可以发现100000000 = 11111111 + 1,所以上面的式子可以拆成两个:

  1 1 1 1 1 1 1 1
- 0 0 0 0 1 0 0 0
-----------------
1 1 1 1 0 1 1 1
+ 0 0 0 0 0 0 0 1
-----------------
1 1 1 1 1 0 0 0

所以负数的补码则是将其对应正数按位取反再加1是这样得出的

同理可以得出-128的补码为100000000 - 10000000 = 10000000,由此可知10000000表示-128的值,8位补码的取值范围[-128,127];

总结

补码系统的最大优点是可以在加法减法处理中,不需因为数字的正负而使用不同的计算方式。只要一种加法电路就可以处理各种有号数加法,而且减法可以用一个数加上另一个数的补码来表示,因此只要有加法电路及补码电路即可完成各种有号数加法及减法,在电路设计上相当方便。

另外,补码系统的0就只有一个表示方式,这点和反码系统不同(在反码系统中,0有二种表示方式),因此在判断数字是否为0时,只要比较一次即可。这就证明了,在正常的加法规则下,可以利用补码得到正数与负数相加的正确结果。换言之,计算机只要部署加法电路和补码电路,就可以完成所有整数的加法。一个字就是方便做运算;

最新文章

  1. 记录一次Quartz2D学习(四)
  2. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q99-Q101)
  3. 默认.htpl改为.htpl
  4. [MySQL Reference Manual] 6 安全性
  5. <构建之法>第十一章、十二章有感
  6. 《暗黑世界GM管理后台系统》部署+功能说明文档
  7. Page.ClientScript.RegisterStartupScript
  8. Oppotunity land---China
  9. C#版二维码生成器
  10. 用CentOS 7打造合适的科研环境
  11. UIPageControl的一个Demo
  12. ORACLE数据库学习之SQL性能优化详解
  13. Vue初始
  14. SQL语句和EF Group by 用法
  15. 1.1 C++布尔类型(bool)
  16. 【linux】Linux软连接和硬链接
  17. 【Unix网络编程】chapter1简介
  18. 第二章 JVM内存分配
  19. Asp.NET MVC 拍卖网站,拆解【1】预览与目录
  20. 如何在makfile中查看变量的值

热门文章

  1. 59、Spark Streaming与Spark SQL结合使用之top3热门商品实时统计案例
  2. ES6 展开运算符 三个点实际功能
  3. Comparison of SIFT Encoded and Deep Learning Features for the Classification and Detection of Esca Disease in Bordeaux Vineyards(分类MobileNet,目标检测 RetinaNet)
  4. 从0开始部署GPU集群-0:基本情况
  5. Remind Me
  6. Python plot_surface(Axes3D)方法:绘制3D图形
  7. 用SC命令 添加或删除windows服务提示OpenSCManager 失败5
  8. js组件常用封装方法。。。。。【组件封装】 ★★★★★★
  9. PLSQL查询执行计划
  10. 泡泡一分钟:Efficient Trajectory Planning for High Speed Flight in Unknown Environments