深入理解计算机系统(3)

本文我们主要讲关于数据的的表示方式:原码,反码和补码。

本文在写作过程中,参考了园中的这篇文章《原码,反码,补码详解》,特此声明。

一原码

计算机中是使用二进制来表示数据的,对于C语言这样的强类型语言,每一个数值类型,都有其范围,例如一个int类型,在32位机器上,其表示的范围如下:

最小值

最大值

有符号整数

-2147483648

217483647

无符号整数

0

4294967295

而如果我们定义了一个int类型,给其的赋值,超出了这个范围,则会出现问题。一般编译器会检查这个问题,会出现编译错误。

为了简单,我们以一个char类型(8位)来进行举例:

最小值

最大值

有符号char

-128

127

无符号char

0

255

那么什么是原码呢:原码是二进制的一种表示方式,其规特点是:

无符号数的每一位都是数字位,

有符号数的最高位是符号位,0表示正数,1表示负数,其余各位表示数值。

1.1无符号数的原码

先说无符号的情况,我们选择几个值

十进制

二进制原码

0

00000000

127

01111111

128

10000000

255

11111111

可见最高位为1,表示十进制的数字128,8位全部都是1,表示255。

例如计算两个数字1和1相加:

十进制

无符号二进制原码表示

加数1

1

00000001

加数2

1

00000001

求和

2

00000010

因此,对于一个无符号数,使用原码表示是正常的。

1.2有符号数的原码

对于有符号数,用原码表示负数,要怎么表示呢?

因为是二进制,也就只有0和1两种符号,于是就定义最高位为符号位:最高位为0的原码,表示一个非负数;最高位为1的原码,表示一个负数。

十进制

无符号原码

有符号原码

0

00000000

00000000

127

01111111

01111111

-127

超出范围,无法表示

11111111

255

11111111

超出范围,无法表示

由上面的表格,我们可以发现原码表示的特点:

1对于一个非负数,在不超出其表示范围的前提下,无符号数和有符号数的原码表示形式是一样的;

2对于一个负数(有符号数),在不超出其表示范围的前提下,其最高位为1,而其余各位与无符号数一样。

那么如果我们在进行计算的时候,使用原码来对两个有符号数进行二进制加法运算会怎么样呢?

两个数都非负数,计算结果是是正确的;

如果有一个数是负数,就会出现问题:

例如:计算如下的两个数字,1和-1相加:

十进制

有符号二进制原码表示

加数1

1

00000001

加数2

-1

10000001

求和

-2

10000010

1+(-1) = -2

这显然,不是我们想要的结果。

如果想用原码表示,就需要计算机对负数的原码进行特殊的处理。如上面的例子,加数2的值是10000001,那么最高位不参与计算,只用于标记这是一个负数。然后将一个正数和另一个负数的加法,转变为两个正数的减法。

即将1+(-1)变为1-1,按照二进制的减法运算法则,得到

十进制

有符号二进制原码表示

被减数

1

00000001

减数

1

00000001

求差

0

00000000

1-1=0

这样就得到了,我们想要的结果。

这样看起来似乎也是可以接受的,那我们再算一些其他的数字,例如1+(-2),按照上面的规则,我们要将其变为1-2

十进制

有符号二进制原码表示

被减数

1

00000001

减数

2

00000002

求差

?

?

由于1小于2,因此1减2,等于2减1,再对结果求其相反数。根据减法的规则,1-2= - (2-1)

十进制

有符号二进制原码表示

被减数

2

00000002

减数

1

00000001

求差

1

00000001

求反

-1

10000001

这样我们也得到了,正确的结果。

但是我们要注意以下几点问题:

1要判断运算数中是否有负数

2可能将加法运算变为减法运算

3可能要求其相反数

可见,本来一个简单的加法的运算,由于负数的问题,变得复杂了。而要处理这些问题,计算机需要一些额外存储空间,以及额外的计算步骤。相应的电路的设计就要更加复杂。

结论:复杂度高,不适合。

二反码

如果使用原码可以很方面的进行计算的话,我也就不会使用反码的方式来表示二进制了。

从上一节可以发现,使用原码的方式在做负数的加法时,比较麻烦。

而负数,表示的是一个正数的相反数,那么我们将一个二进制数按位取反,会有怎样的现象呢?

我们看以下这些数字。

原始值

无符号数原码

原码按位取反

去反后的值

0

00000000

11111111

255

127

01111111

10000000

128

255

11111111

00000000

0

可以看出,无符号数,二进制按位取反,其结果为原值被最大值(255)减,即:

0按位取反表示255 – 0 = 255

127按位取反表示 255 – 127 = 128

255按位取反表示 255 – 255 = 0

那么对于有符号数有是什么样呢?我们看以下有符号数字,原码符号位不变,数字位按位取反的计算结果

原始值

有符号数原码

原码按位取反

取反后的值

-127

11111111

10000000

-0

-3

10000011

11111100

-124

-1

10000001

11111110

-126

0

00000000

01111111

127

1

00000001

01111110

126

3

00000011

01111100

124

127

01111111

00000000

0

可以看出,有符号数,除了符号位,二进制按位取反,其结果的绝对值为原值被最大值(127)减,即:

-127按位取反表示- (127 – 127 ) = -0

-3按位取反表示 – (127 – 3 ) = - 124

0按位取反表示 +(127 – 0 )= 127

3按位取反表示+(127 – 3) = 124

127按位取反表示+(127 – 127 )= 0

那么如果我们在计算有符号数加法时,我们可以得到如下的四种情况

使用原码

使用原码取反

正数

负数

我们按照这四种情况分别计算1 + (-1),使用二进制加法,看看有什么有趣的现象

1正数使用机器码,负数使用机器码

在计算符号不同的两个数值的加法时,最终结果的符合与绝对值大的那个相同。

但是如果两个数值不为0,且互为相反数,那最终的结果的符号就不一定了。

十进制

有符号二进制原码表示

加数1

1

00000001

加数2

-1

10000001

求和

x0000010

x=0

2

00000010

X=1

-2

10000010

无论x是正还是负,结果似乎都不正确。

2正数使用机器码,负数使用机器码按位取反

十进制

有符号二进制原码表示

加数1

1

00000001

加数2(按位取反)

-2

11111101

求和

-1

10000001

我们定义最高位符号位的值是x,

对于1 + (-2) ,由于负数的绝对值(2)大于正数的绝对值(1),因此可以确定,x的值是1。

也就是首先能确定最终结果是个负数,然后计算其后面的数值位,

七位的:0000001

加上

七位的:1111101

得到

七位的:1111110

再加上符号位,得到

八位的:11111110

按照前提,这是一个负数,其真值要对其数值为按位取反,得到10000001,即 -1。

这个结果,貌似很好。但是如果计算1+ (-1)会怎么样呢?

十进制

有符号二进制原码表示

加数1

1

00000001

加数2(按位取反)

-1

11111110

求和

??

X1111111

X=0

127

01111111

X=1(按位取反)

-0

10000000

这里在计算00000001和11111110时,由于1和-1的绝对值相等,那么其符号就无法确定。那么我们先不考虑符号位,将数值位进行二进制加法,然后得到x1111111。

那么这时候,x的值有两种可能:

X = 0 ,那这个数字是正数,正数值为:127

X = 1,那这个数字是负数,负数在本环境下是要按位取反来得到其真值的,因此

11111111按位取反,得到10000000,即真值为- 0

那么到底x等于几呢?这个似乎也是个不太好说的问题。

对于 -0 和 127,貌似 -0更加贴近最终的答案,那可以人为的规定,如果负数按位取反,在计算时,符号位优先使用1,即x值无法确定时,优先取1。

我们再计算一下-1 + (-1)

十进制

有符号二进制原码表示

加数1(按位取反)

-1

11111110

加数2(按位取反)

-1

11111110

求和

-124

11111100(溢出)

按位取反

-3

10000011

3正数使用机器码按位取反,负数使用机器码

十进制

有符号二进制原码表示

加数1(按位取反)

2

01111101

加数2

-1

10000001

求和

126

01111110

按位取反

1

00000001

十进制

有符号二进制原码表示

加数1(按位取反)

1

01111110

加数2

-1

10000001

求和

??

X1111111

X=0(按位取反)

0

00000000

X=1

-127

11111111

根据第2中情况的分析,我们可以得到上表的结果。

此时,x的值仍然有两种情况,

X优先取0,则得到结果 0

X优先取1,则得到结果-127

那么这种情况下可以规定,x值优先取0。

我们计算1 + 1

十进制

有符号二进制原码表示

加数1(按位取反)

1

01111110

加数2(按位取反)

1

01111110

求和

124

01111100(溢出)

按位取反

3

00000011

4正数使用机器码取反,负数使用机器码取反

十进制

有符号二进制原码表示

加数1(按位取反)

1

01111110

加数2(按位取反)

-1

11111110

求和

??

X1111100(溢出)

X=0(按位取反)

3

00000011

X=1(按位取反)

-3

10000011

归纳上面的规律

序号

名称

1+1

2+2

1+(-1)

1+(-2)

-1+(-1)

-2+(-2)

1

正原负原码

2

4

2或-2

-3

-2

-4

2

正原负反码

2

4

-0或127

-1

-3

-1

3

正反负原码

3

1

0或-127

-0

-2

-4

4

正反负反码

3

3或-3

-3

可以看到,有价值的是1和2,将两种组合,应该可以计算出正确的结果。

正+正

正+负

负+负

结论

1

Y

N

Y

符号相同成立

2

Y

Y

N

符号不同成立,双正成立

我们使用1和2结合,得到如下二进制加法计算规则:

在符号相同时,符号位不变,数值位直接进行二进制加法。

在符号不同时,符号位由绝对值大的数字的符号决定,如果绝对值相同,优先使用负值,而负数将数值部分,用机器码按位取反后,再与正数进行二进制加法。

那么按照这个规则,在进行计算机的运算处理时,需要考虑哪些问题呢?

1要判断数字的符号

2要根据符号相同和不同采取不同的策略

这里面,1是必须要考虑的,因为有符号数字,必须要有一个位来标识符号。

有了这一点,就可以解决同符号的加法问题了。

对于不同符号的加法,如果正数和负数绝对值相同,仍然是个不好处理的问题。

结论:复杂度低,但是还有待改善

三补码

上节讲的,正数用机器码表示,负数用机器码按位取反的表示方法,就是反码。

而且,一个数字的反码所表示的数字,与自身的和,是固定值——这个数值所能表示的最大值。

对于8位无符号数值类型的变量,其最大值是255。

而7位的话,最大值是127。

因此,对于1+(-2),可以先确定符号位是1,然后计算000 0001和000 0010(取反)的和

即,000 0001 + 111 1101,结果是111 1110。再取反,得到000 0001。再补上最高位的1

得到,1000 0001,结果就是-1。

当正值和负值的绝对值相同的时候,例如 1+(-1),我们规定此时符号0,然后计算

000 0001和000 0001(取反)的和,即000 0001 + 111 1110,结果是111 1111。由于这个数字式正数,因此其值为127。注意,这里的前提是,正数保持原样,负数按位取反。

那么127,代表什么呢?

对于一个char字符,除去其最高位符号位,还剩下7位。

7位二进制的表示范围是000 0000到111 1111,即0到127,共128个数字。

从000 0000开始加1,加127次达到最大值。

达到最大值之后,如果再加1,就得到1 000 0000。而这里的最高位因为溢出而会被舍去,因此只存储了000 0000这7位值,这个值就回到了最初。

对于钟表来讲,从1开始,依次加1,加到12时,达到了最大值。再加1的话,就得到了13,而13由于溢出,因此只保留了1。

因此,我们可以得到这个结果,如果最小值从1开始,那么最大值就是周期。

因此钟表的周期是12。

那么7位二进制数的周期是多少呢?从0到127,为了和钟表统一,我们将其整体加1:

从1开始,最大到128。这样可以推出,7位二进制的周期是128。

也就是说,7位二进制数,表示的数字,具备这样的特性。

数字N与其按位取反的数字M,必有N+M=周期-1。

因此N=周期-1-M。

而周期会溢出,因此在N上增加若干整数倍周期,与没有增加周期,其结果是一样的。

因此有:周期+N = 周期 – 1 – M。注意这里的相等,是去掉溢出位之后相等。

那么所有两边都去掉一个周期。

就得到

N = -1 – M即N=  -(M+1)

因此就有 -N =  M + 1

根据同余的特性,对于任意数字X,X在7位二进制数字表示范围内:

有X+(-N) =  X+ M+1

而M为N的按位取反(反码)。所以对于一个负数,在其二进制反码的基础上在加上数字1,就得到了其同余的数值。这就是现在计算机中实际表示数据的形式——二进制的补码。

以上的推导过程,不是严格的数学证明,只是为了方便理解。

而我们用补码方式来进行计算1 + (-1)

首先确定符号位的值是0

因此计算000 0001 和 000 0001(求补)的和,即

000 0001 + 111 1111 因此,得到000 0000,再补充上最高位0,

得到0 000 0000,即数字0。

完美解决了,在使用反码时,正数情况下的127而负数情况下-0的问题。

结论:使用补码存储数值,可以用加法的运算处理减法。计算相反数的加法,也正确。

可以使用。

四总结

数学是计算机的基础,从计算机的二进制存储可见一斑。因此我们在学习计算机技术的同时,加强数学知识的学习,是非常重要的。

转载于:https://www.cnblogs.com/asenyang/p/5559236.html

深入理解计算机系统(3)相关推荐

  1. 《深入理解计算机系统》读书随笔-位操作

    最近开始读<深入理解计算机系统>这本书.对于书中提到的从程序员的角度解读计算机系统这一说法非常感兴趣,所以决定好好读一读.从开始接触计算机编程就是站在一个高级语言的层次,虽然对编译原理,操 ...

  2. 【组队学习】【32期】深入理解计算机系统

    深入理解计算机系统 航路开辟者:李岳昆.易远哲 领航员:初晓宇 航海士:叶前坤.沈豪 基本信息 开源内容:https://github.com/datawhalechina/team-learning ...

  3. 深入理解计算机系统 -资料整理 高清中文版_在所不辞的博客-CSDN博客_深入理解计算机系统第四版pdf

    深入理解计算机系统 -资料整理 高清中文版_在所不辞的博客-CSDN博客_深入理解计算机系统第四版pdf

  4. 《深入理解计算机系统-程序结构》读书笔记

    1.计算机系统漫游 计算机系统是由硬件和系统软件组成的,他们共同工作来运行应用程序.在<深入理解计算机系统>一书中将会学到很多实践的技巧.例如:了解编译器是如何实现过程调用的.避免缓冲区溢 ...

  5. csapp 、sicp 、深入理解计算机系统、 计算机程序的构造和解释

    CSAPP 第一版的英文版 深入理解计算机系统第一版中文版  这个是csdn账号  这里上传文件大小在10M以内  这个pdf是19+M的 深入理解计算机系统第二版的中文版下载 第一版英文版的介绍原书 ...

  6. 《深入理解计算机系统》第七章读书笔记

    <深入理解计算机系统>第七章读书笔记 第七章:连接 连接 1.连接:将各种代码和数据部分收集起来并组合成为一个单一文件的过程.这个文件可被加载或拷贝到存储器并执行. 2.连接可以执行于编译 ...

  7. 深入理解计算机系统:网络编程 上

    一直以来对计算机网络比较感兴趣,但是无奈大学计算机网络的学习非常表面,已经忘得差不多了.毕业后读了一些网络方面的书,对网络知识的冰山一角有了一些感悟. 随着网络方面的书越读越多,不懂的地方也越来越多. ...

  8. bilibili深入理解计算机系统笔记(2):第一次代码重构,汇编模拟器,递归,指令周期实现。

    文章目录 深入理解计算机系统笔记(2) 第一次代码重构 可变参数输出print函数 bitmap学习 P10 有限自动机 指令周期 递归求和函数c语言和汇编语言 回调函数的实现 call和ret指令的 ...

  9. bilibili深入理解计算机系统笔记(1):汇编模拟器能跑了

    文章目录 深入理解计算机系统笔记 P1笔记 p2笔记 p3笔记 p4笔记 汇编模拟器(p5-7) 封装访存接口 输出计算机状态 实现指令 call指令的实现 bug 积累 include重复包含的bu ...

最新文章

  1. js按钮触发网页提醒_jquery,js页面加载时自动点击触发jq按钮-Go语言中文社区
  2. python图像识别步骤_利用百度智能云结合Python体验图像识别(转载来自qylruirui)
  3. Comet OJ(Contest #8)-C符文能量【dp】
  4. oracle取某时间段的数据
  5. 精彩编码 【进制转换】
  6. 玩转Ubuntu(Linux原生游戏 超级企鹅(SuperTux))
  7. NGFW中数据包转发流程
  8. Linux 重新加载 nginx 配置命令
  9. Deep-learning augmented RNA-seq analysis of transcript splicing | 用深度学习预测可变剪切
  10. 红外遥控智能小车 源码
  11. React Native-9.React Native Touchable组件详解
  12. 国产开源数据库:腾讯云TBase在分布式HTAP领域的探索与实践
  13. 第一阶段项目(2 body)
  14. 《MAC OS X 技术内幕》读书笔记第一章:MAC OS X的起源
  15. 激光雷达相机外参标定
  16. 动态规划特训:切木棍(UVA10003)区间切分dp
  17. 双CPU与单CPU有什么区别,有什么优势?
  18. 生物质的特性对其与煤共气化过程的影响
  19. 如何区别随身WiFi板子是什么芯片
  20. 虚拟机的vmem lck到底是个啥玩意 用虚拟机很有可能一不小心就把虚拟机搞崩了如何解决

热门文章

  1. HTTP Status 400
  2. shardingjdbc全局表_sharding-jdbc实现按年分库按月分表
  3. 2020年春季学期教学日历
  4. 2021春季学期-创新设计与实践-课程结构设计
  5. 高频小功率三极管-S9018
  6. 高压测试平台:高压包产生高电压基本测试参数
  7. java环境配置好了还不行,java配置环境java不行
  8. mysql 分区表_分享一份生产环境mysql数据库分区表改造方案
  9. 显示计算机硬盘驱动器更改,笔记本硬盘驱动器的字母怎么修改?笔记本修改硬盘驱动器字母的方法...
  10. java binarytreenode_LeetCode算法题-Binary Tree Paths(Java实现-3种解法)