《深入理解计算机系统》笔记-信息的表示和处理

记录:如何缩放csdn中的图片:在#pic_center末尾加上=50%x50%#pic_left:左对齐。

视频地址:https://www.bilibili.com/video/BV1kE411X7S5?p=16&spm_id_from=pageDriver

二、信息的表示和处理

“转换” 的概念在数据表示中的反映

在这里插入图片描述

在这里插入图片描述

1. 信息存储

1.1 信息的二进制编码

  • 机器级数据分两类:
    • 数值数据
    • 非数值数据
  • 计算机内部所有信息都是二进制进行编码,原因:
    • 制造二个稳定态的物理器件容易(电位高/低,脉冲有/无,正/负极)
    • 二进制编码、计数、运算规则简单
    • 正好与逻辑命题 真/假 对应,便于逻辑运算
    • 可方便地用逻辑电路实现算术运算
  • 真值和机器数
    • 真值:真正的值,即:现实中带正负号的数
    • 机器数:用0和1编码的计算机内部的 0/1 序列

1.2 数值数据的表示

  • 数值数据表示的三要素

    • 进位计数制
    • 定、浮点表示
    • 如何用二进制编码
      即:要确定一个数值数据的值必须先确定这三个要素。
      例如,20137564的值是多少?——答案是:不知道!
  • 进位计数制

    • 十进制、二进制、十六进制、八进制数及其相互转换
  • 定/浮点表示(解决小数点问题)

    • 定点整数、定点小数
    • 浮点数(可用一个定点小数和一个定点整数来表示)
  • 定点数的编码(解决正负号问题)

    • 原码、补码、反码、移码(反码很少用)

下面来分别看数值数据表示的三要素。

1.2.1 进制计数制

在这里插入图片描述
在这里插入图片描述

日常生活中用十进制、计算机中用二进制表示所有信息,为什么还要引入 八进制/十六进制 呢?
八进制 / 十六进制 是二进制的简便表示。便于阅读和书写(它们之间对应简单,转换容易)

二进制:Binary(用后缀“B”表示)
八进制:Octal(用后缀“O”表示)
十六进制:Hexadecimal(用后缀“H”,或前缀“Ox”表示)

1.2.2 进制数之间的转换 和 定/浮点表示

直接看例子:

  1. R进制数——>十进制
    在这里插入图片描述

  2. 十进制——>二进制,再转换为 8/16 进制
    在这里插入图片描述

    有个问题:小数点在计算机中是如何表示的?

    再看一种情况:
    在这里插入图片描述

现在来看上面的问题:

  • 计算机中只能通过 约定小数点的位置 来表示小数点
    • 小数点位置约定在固定位置的数称为 定点数
    • 小数点位置约定在可浮动的数称为 浮点数
  • 定点小数用来表示浮点数的尾数部分
  • 定点整数用来表示整数,分为 带符号整数和无符号整数
  • 在这里插入图片描述
    在这里插入图片描述
    其中,S取值为0或1,用来决定数X的符号;M是一个二进制定点小数,称为数X的尾数(mantissa);E是一个二进制定点整数,称为数X的阶或指数(exponent);R是基数(radix、base),可以为2、4和16等。计算机中只要表示S、M和E三个信息,就能确定X的值,这称为浮点数

即:要解决数值数据的表示问题,只要解决定点数的编码问题!

1.2.3 定点数的编码

原码表示
在这里插入图片描述

易理解,但是有以下缺点:

  • 0的表示不唯一,故不利于编程
  • 加、减运算方式不统一
  • 需额外对符号位进行处理,不利于硬件设计
  • 特别当a < b时,实现a - b比较困难

从50年代开始,整数都采用补码表示,浮点数的尾数还是用原码定点小数表示。

补码表示

在这里插入图片描述

注意:这里X是真值,后面还有变形补码

计算机中的运算器是模运算系统

在这里插入图片描述

一个负数的补码等于将对应正数补码 各位取反,末位加一

变形补码的表示

在这里插入图片描述

说了这么多,记住一句话就行:正数的补码就是自己;负数的补码是:除符号位外,各位取反,然后总体+1。

再看几个特殊数的补码:

在这里插入图片描述

移码表示

在这里插入图片描述


今天被 在8进制位中 -128的补码如何表示搞晕,下面系统整理一下关于 -128 ,+128,-0,+0,-1 的反码补码表示:

真值原码反码补码
+00000 00000000 00001 | 0000 0000
-01000 00001111 11111 | 0000 0000
+128
-1280 | 1000 0000

即原码、反码、补码的范围:(字长是8位二进制数)

原码 : -127~127
反码 : -127~127
补码 : -128~127

2. 整数表示

整数类型分为:无符号整数 和 带符号整数

C语言支持的基本数据类型

在这里插入图片描述

2.1 无符号整数

  • 机器中字的位排列顺序有两种方式:
    1. 高到低位从左到右(LSB)——一般采用这个
    2. 高到低位从右到左(MSB)
  • 一般在全部是正数运算且不出现负值结果的场合下,可使用无符号
    数表示。例如,地址运算,编号表示,等等
  • 无符号整数的编码中 没有符号位
  • 能表示的最大值大于位数相同的带符号整数的最大值

2.2 带符号整数

  • 最高位用 “0” 表示正数,“1” 表示负数。
  • 有三种定点编码方式(前面已讲过)
    1. 原码:定点小数,用来表示浮点数的尾数
    2. 移码:定点整数,用来表示浮点数的阶(指数)
    3. 补码:50年代以来,所有计算机都用补码来表示带符号整数
  • 为什么用补码表示带符号整数?
    • 补码运算系统是模运算系统,加、减运算统一
    • 数0的表示唯一,方便使用
    • 比原码多表示一个最小负数

2.3 C语言程序中的整数

常在一个数的后面加一个“u”或“U”表示无符号数

若同时有无符号和带符号整数,则C编译器将带符号整数强制转换为无符号数

看例子:假定以下关系表达式在32位用补码表示的机器上执行,结果是什么?

在这里插入图片描述

带*的结果与常规预想的相反!


整理:整数在计算机中是如何存储的?

  • 无符号整数按其二进制的形式直接存储
  • 有符号整数按其补码的形式存储

以8位二进制数为例:

  • 无符号整数存储范围:0~2^8 - 1 [0, 255]
  • 有符号整数存储范围:-2^7 ~ 2^7 - 1 [-128, 127]

练习:考虑以下C代码

int x = -1;
unsigned u = 2147483648;
printf("x = %u = %d \n", x, x);
printf("u = %u = %d \n", u, u);

在32位机器上运行上述代码时,它们的输出结果是什么?Why?

先看输出结果:

x = 4294967295 = -1
u = 2147483648 = -2147483648

解析:

%d 表示数据按十进制有符号整型数输入或输出;
%u 表示数据按十进制无符号整型数输入或输出。

int x = -1 是有符号的整数,在计算机中用补码的形式存储,即“1111 … … 1111”(共32位)。当作为32位无符号整数解析时,“1111 … … 1111”的值为 2^31 + 2^30 + … + 2^0 = 2^32 - 1 = 4294967296 - 1 = 4294967295。

unsigned u = 2147483648 是无符号的整数,在计算机中直接存储,即“1000 … … 0000”.当作为有符号整型数解析时,它是某个数的补码;而我们又知道32位带符号整数的最小负数 -2^31 = -2147483648 的补码为 “1000 … … 0000”,所以unsigned u = 2147483648 作为有符号整型数时,代表的值为 -2147483648。

3. 浮点数的表示

实数类型分为:单精度浮点数、双精度浮点数 和 扩展精度浮点数

对于二进制实数:

在这里插入图片描述

(规格化形式:小数点前只有一位非0数)
只要对尾数和指数分别编码,就可表示一个浮点数(即:实数)

3.1 浮点数的表示范围

在这里插入图片描述

第0位数符S;
第1~8位为8位移码表示阶码E(偏置常数为128);
第9~31位为24位二进制原码小数表示的尾数M。
规格化尾数的小数点后第一位总是1,故规定第一位默认的“1”不明显表示出来。这样可用23个数位表示24位尾数。

  • 在这里插入图片描述

因为原码对称,故其表示范围关于原点对称。

在这里插入图片描述

3.2 IEEE754规格化数字的表示

早期的计算机各自定义自己的浮点数格式,那么就有个问题:浮点数表示不统一会带来什么问题?——机器之间传送数据时,带来麻烦

现在所有通用计算机都采用IEEE 754来表示浮点数

Single Precision(单精度):
在这里插入图片描述

  • Sign bit: 1 表示negative ; 0表示positive
  • Exponent(阶码):
    • SP规格化阶码范围为0000 0001 (-126) ~ 1111 1110 (127)
    • bias为127 (single), 1023 (double)
    • 全0和全1用来表示特殊值!
  • Significand(部分尾数):
    • 规格化尾数最高位总是1,所以隐含表示,省1位
    • 1 + 23 bits ( single),1 + 52 bits (double)

在这里插入图片描述

例1:机器数转换为真值

已知float型变量x的机器数为BEE00000H,求x的值是多少?

先将十六进制数字转换为二进制:1 | 011 11101 | 110 0000 0000 0000 0000 0000

  • 符号:1 (负数)
  • 阶(指数):
    • 阶码: 0111 1101B = 125
    • 阶码的值: 125 - 127 = -2
  • 尾数数值部分:
    • 1 + 1x2^-1+ 1x2^-2 + 0x2^-3 + 0x2^-4 + 0x2^-5 +…=1+2^-1 +2^-2 = 1+0.5 +0.25 = 1.75
  • 真值: -1.75x2^-2 = - 0.4375

例2:真值转换为机器数

已知float型变量x的值为-12.75,求x的机器数是多少?

先将十进制数转化为二进制:-12.75 = -1100.11B = -1.10011B x 2^3

  • 符号:S = 1
  • 阶码:E = 127 + 3 = 128 + 2 = 1000 0010
  • 显式表示的部分尾数S = 100 1100 0000 0000 0000 0000

因此,x的机器数为:1 1000 0010 100 1100 0000 0000 0000 0000;转换为十六进制:C14C0000H

*4. 非数值数据的表示

4.1 逻辑数据的编码表示

计算机中何时会用到逻辑数据?

  • 表示逻辑(关系)表达式中的逻辑值:真/假

N位二进制数(位串)可表示N个逻辑数据。

在运算时按位进行。

逻辑数据和数值数据在形式上并无差别,也是一串0/1序列,计算机靠指令来识别。

4.2 西文字符的编码表示

特点:

  • 是一种拼音文字,用有限几个字母可拼写出所有单词
  • 只需对有限个字母和数学符号、标点符号等辅助字符编码
  • 所有字符总数不超过256个,使用7或8个二进位可表示

表示(常用编码为7位ASCII码):

  • 十进制数字:0/1/2…/9
  • 英文字母:A/B/…/Z/a/b/…/z
  • 专用符号:+/-/%/*/&/……
  • 控制字符(不可打印或显示)

4.3 汉字及国际字符的编码表示

汉字特点:

  • 汉字是表意文字,一个字就是一个方块图形
  • 汉字数量巨大,总数超过6万字,给汉字在计算机内部的表示、汉字的传输与交换、汉字的输入和输出等带来了一系列问题。

编码形式:

  • 输入码:对汉字用相应按键进行编码表示,用于输入
  • 内码:用于在系统中进行存储、查找、传送等处理
  • 字模点阵或轮廓描述: 描述汉字字模点阵或轮廓,用于显示/打印

4.4 GB2312-80字符集

由三部分组成:

  1. 字母、数字和各种符号,包括英文、俄文、日文平假名与片假名、罗马字母、汉语拼音等共687个
  2. 一级常用汉字,共3755个,按汉语拼音排列
  3. 二级常用汉字,共3008个,不太常用,按偏旁部首排列

汉字的区位码:

  • 码表由94行、94列组成,行号为区号,列号为位号,各占7位
  • 指出汉字在码表中的位置,共14位,区号在左、位号在右

汉字的国标码:

  • 每个汉字的区号和位号各自加上32(20H),得到其“国标码”
  • 国标码中区号和位号各占7位。在计算机内部,为方便处理与存储,前面添一个0,构成一个字节

补充:汉字内码

  • 至少需2个字节才能表示一个汉字内码。(2^16=65536)

  • 可在GB2312国标码的基础上产生汉字内码

    • 为与ASCII码区别,将国标码的两个字节的第一位置“1”后得到一种汉字内码(可以有不同的编码方案)

    例:汉字“大”在码表中位于第20行、第83列。因此区位码为0010100 1010011,在区、位码上各加32得到两个字节编码,即 0 01 10100 0 11 10011B=3473H。前面的34H和字符“4”的ACSII码相同,后面的73H和字符“s”的ACSII码相同,但是,将每个字节的最高位各设为“1”后,就得到其内码:B4F3H (1 01 101001 11 10011B),因而不会和ASCII码混淆。

4.5 多媒体信息的表示

图形、图像、音频、视频等信息在机器内部也用0和1表示

  • 图形用构建图形的直线或曲线的坐标点及控制点来描述,而这些坐标点或控制点则用数值数据描述
  • 图像用构成图像的点(像素)的亮度、颜色或灰度等信息来描述,这些亮度或颜色等值则用数值数据描述
  • 音频信息通过对模拟声音进行采样、量化(用二进制编码)来获得,因此量化后得到的是一个数值数据序列(随时间变化)
  • 视频信息描述的是随时间变化的图像(每一幅图像称为一帧)
  • 音乐信息(MIDI)通过对演奏的乐器、乐谱等相关的各类信息用0和1进行编码来描述
  • …….

多媒体信息用一个复杂的数据结构来描述,其中的基本数据或者是数值数据,或者是用0/1编码的非数值数据

5. 数据宽度和存储容量的单位

比特(bit,位)是计算机中处理、存储、传输信息的最小单位。

二进制信息最基本的计量单位是 “字节”(Byte)

  • 现代计算机中,存储器按字节编址
  • 字节是最小可寻址单位
  • 如果以字节为一个排列单位,则LSB表示最低有效字节,MSB表示最高有效字节

除比特(位)和字节外,还经常使用 “字”(word) 作为单位

注意:“字” 和 “字长” 是不同的!

“字”表示被处理信息的单位,用来度量数据类型的宽度。

“字长” 指的是数据通路的宽度。
“字长”等于CPU内部总线的宽度、运算器的位数、通用寄存器的宽度(这些部件的宽度都是一样的)

补充:数据通路 指CPU内部数据流经的路径以及路径上的部件,主要是CPU内部进行数据运算、存储和传送的部件,这些部件的宽度基本上要一致,才能相互匹配。

数据量的度量单位

存储二进制信息时的度量单位要比字节或字大得多。

容量常用单位:

  • “千字节”(KB),1KB = 2^10字节 = 1024B
  • “兆字节”(MB),1MB = 2^20字节 = 1024KB
  • “千兆字节”(GB),1GB = 2^30字节 = 1024MB
  • “兆兆字节”(TB),1TB = 2^40字节 = 1024GB

通信中的 带宽 使用的单位:

  • “千比特/秒”(kb/s),1kbps=103 b/s=1000 bps
  • “兆比特/秒”(Mb/s),1Mbps=106 b/s =1000 kbps
  • “千兆比特/秒”(Gb/s),1Gbps=109 b/s =1000 Mbps
  • “兆兆比特/秒”(Tb/s),1Tbps=1012 b/s =1000 Gbps

b表示 比特(位),B表示 字节

程序中数据类型的宽度

在这里插入图片描述

6. 数据的存储和排列顺序

80年代开始,几乎所有通用计算机都采用字节编址。

在高级语言中声明的基本数据类型有char、short、int、long、long long、float、double、long double等各种不同长度数据。

一个基本数据可能会占用多个存储单元:

  • 例如,若 int 型变量x = -10, x的存放地址为100,其机器数为FFFFFFF6H(计算机中存放带符号数的补码),占4个单元
    考虑:

    • 变量的地址是其最大地址还是最小地址?——最小地址,即x存放在100#~103#!
    • 多个字节在存储单元中存放的顺序如何?——大端方式/小端方式
  • 再例如,若 int i = -65535,存放在100号单元(占100~103),则用“取数”指令访问100号单元取出 i 时,必须清楚 i 的4个字节是如何存放的。
    在这里插入图片描述

    有些机器两种方式都支持,可通过特定控制位来设定采用哪种方式。

7. 整数的运算

7.1 整数加减法

指针、地址等通常被说明为无符号整数,因而在进行指针或地址运算时,需要进行无符号整数的加、减运算。

无符号整数和带符号整数的加、减运算电路完全一样,这个运算电路称为整数加减运算部件,基于带标志加法器实现

计算机中的加法器,因为只有n位,所以是一种模2^n运算系统!

所有运算电路的核心

  • 计算机中所有运算都基于加法器实现!
  • 加法器不知道所运算的是带符号数还是无符号数。
  • 加法器不判定对错,总是取低n位作为结果,并生成标志信息。

7.2 整数乘法

7.2.1 运算规则

通常,高级语言中两个n位整数相乘得到的结果通常也是一个n位整数,也即结果只取2n位乘积中的低n位。

在计算机内部,一定有x² ≥ 0吗?
若x是带符号整数,则不一定;若x是浮点数,则一定!

  • 例:在C语言中,参加运算的两个操作数的类型和结果的类型必须一致,如果不一致则会先转换为一致的数据类型再进行计算。

    int mul(int x, int y) {
    	int z = x * y;
    	return z;
    }
    // x*y 被转换为乘法指令,在乘法运算电路中得到的乘积是64位,但是,只取其低32位赋给z。
    

    在这里插入图片描述

结论:两个整数的机器数X和Y的乘积结果X*Y的高n位可以用来判断溢出,规则如下:

  • 无符号:若高n位全0,则不溢出,否则溢出
  • 带符号:若高n位全0或全1且等于低n位的最高位,则不溢出。

例:
在这里插入图片描述

7.2.2 整数乘法溢出漏洞

例:以下程序存在什么漏洞,引起该漏洞的原因是什么?

/* 复制数组到堆中,count为数组元素个数*/
int copy_array(int *array, int count) {
	int i;
	/* 在堆区申请一块内存*/
	int *myarray = (int *) malloc(count*sizeof(int));
	if (myarray == NULL)
		return -1;
	for (i = 0; i < count; i++)
        // 攻击者可构造特殊参数来触发整数溢出,以一段预设信息覆盖一个已分配的堆缓冲区,造成远程服务器崩溃或者改变内存数据并执行任意代码。
		myarray[i] = array[i];	
	return count;
}

当参数count很大时,则count*sizeof(int)会溢出。
如count=230+1时,count*sizeof(int)=4。
会导致堆(heap)中大量数据被破坏!

7.2.3 变量与常数之间的乘运算

整数乘法运算比移位和加法等运算所用时间长,通常一次乘法运算需要多个时钟周期,而一次移位、加法和减法等运算只要一个或更少的时钟周期,因此,编译器在处理变量与常数相乘时,往往以移位、加法和减法的组合运算来代替乘法运算。

例,对于表达式x*20,编译器可以利用20=16+4=2^4 + 2^2,将x*20转换为(x<<4)+(x<<2),这样,一次乘法转换成了两次移位和一次加法。

不管是无符号数还是带符号整数的乘法,即使乘积溢出时,利用移位和加减运算组合的方式得到的结果都是和采用直接相乘的结果是一样的。

7.3 整数除法

7.3.1 运算规则

先看一个有关溢出的问题:对于带符号整数来说,n位整数除以n位整数,除 -2^(n-1) / -1= 2^(n-1) 会发生溢出外,其余情况都不会发生溢出。Why?

因为商的绝对值不可能比被除数的绝对值更大,因而不会发生溢出,也就不会像整数乘法运算那样发生整数溢出漏洞。

整数除法,其商也是整数,所以在不能整除时需要进行舍入,通常按照朝0方向舍入,即正数商取比自身小的最接近整数(Floor,地板),负数商取比自身大的最接近整数(Ceiling,天板)。

注意:整数除法时,除数不能为0,否则会发生“异常”,此时需要调出操作系统中的异常处理程序来处理。

7.3.2 变量与常数之间的除运算

问题:对于整数除法运算,由于计算机中除法运算比较复杂,而且不能用流水线方式实现,所以一次除法运算大致需要30个或更多个时钟周期,比乘法指令的时间还要长!

解决:为了缩短除法运算的时间,编译器在处理一个变量与一个2的幂次形式的整数相除时,常采用右移运算来实现。

  • 无符号、带符号正整数:逻辑右移,移出的低位直接丢弃。

  • 带符号的负整数:算术右移,不过要先加偏移量(2^k - 1),然后再右移k位,低位截断(这里K 是右移位数)

    算术右移需要考虑符号位,右移一位,若符号位为1,就在左边补1,;否则,就补0。

    逻辑右移只需左边补0。

例1:(无符号整数)12 / 4=3 —— 0000 1100 >> 2 = 0000 0011;
(带符号负整数)-12 / 4 = -3 —— 1111 0100 >> 2 = 1111 1101

例2:(无符号数) 14 / 4=3 —— 0000 1110 >> 2 = 0000 0011;
(带符号负整数)-14 / 4= -3

若直接截断,则1111 0010 >> 2 = 1111 1100 = -4 ≠ -3
应先纠偏,再右移: k=2, 故(-14+2² - 1)/4=-3
即: 1111 0010+ 0000 0011 =1111 0101
1111 0101 >> 2 = 1111 1101 = -3

8. 浮点数的运算

在这里插入图片描述

上述运算结果可能出现以下几种情况:

  • 阶码上溢:一个正指数超过了最大允许值 =〉+∞/-∞/溢出
    SP最大指数为多少? 127
  • 阶码下溢:一个负指数超过了最小允许值 =〉+0/-0
    SP最小指数为多少?-126
  • 尾数溢出:最高有效位有进位 =〉右规
    尾数溢出,结果不一定溢出
  • 非规格化尾数:数值部分高位为0 =〉左规
  • 右规或对阶时,右段有效位丢失 =〉尾数舍入

IEEE建议实现时为每种异常情况提供一个自陷允许位。若某异常对应的位为1,则发生相应异常时,就调用一个特定的异常处理程序执行。

IEEE 754 标准规定的五种异常情况

  1. 无效运算(无意义)
    • 运算时有一个数是非有限数,如:
      加 / 减∞、0 * ∞、∞/∞等
    • 结果无效,如:
      源操作数是NaN、0/0、x REM 0、∞ REM y 等
  2. 除以0(即:无穷大)
  3. 数太大(阶上溢): 对于SP,指阶码E >1111 1110 (指数大于127)
  4. 数太小(阶下溢) : 对于SP,指阶码E < 0000 0001(指数小于-126 )
  5. 结果不精确(舍入时引起),例如1/3、1/10等不能精确表示成浮点数

上述情况硬件可以捕捉到,因此这些异常可设定让硬件处理,也可设定让软件处理。让硬件处理时,称为硬件陷阱。

进行尾数加减运算前,必须“对阶”!

“对阶”操作:目的是使两数阶码相等

  • 小阶向大阶看齐,阶小的那个数的尾数右移,右移位数等于两个阶码差的绝对值
  • IEEE 754尾数右移时,要将隐含的“1”移到小数部分,高位补0,移出
    的低位保留到特定的“附加位”上

浮点数加法运算举例

在这里插入图片描述

问题:为何IEEE 754 加减运算右规时最多只需一次?
因为即使是两个最大的尾数相加,得到的和的尾数也不会达到4,故尾数的整数部分最多有两位,保留一个隐含的“1”后,最多只有一位被右移到小数部分。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ClimberCoding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值