深入理解计算机系统(csapp)(第二章信息的表示与处理)

第二章 信息的表示和处理

现代计算机存储和处理的信息以二值信号表示。
无符号编码基于传统的二进制表示法,调式大于或者等于零的数字。
补码编码是表示有符号整数的最常见的方式,有符号整数就可以为正或者为负的数字。浮点数编码是表示实数的科学计数法的以2为基数的整数和实数运算。
计算机表示法是用有限的位对一个数字编码,因此当结果太大时会造成溢出,产生错误的结果。
整数的表示虽然只能编码一个相对较小的数值范围,但这种表示时精确的;而浮点数虽然可以编码一个较大的数值范围,但是这种表示只是近似的。
在这里插入图片描述

2.1 信息存储

大多数计算机使用8位的块,或者字节(byte),作为最小的可寻址的内存单位,而不是访问内存中单独的位。
机器级程序将内存视为一个非常大的数组,称为虚拟内存,内存的每一个字节都由一个唯一的数字来标识,称为它的地址,所有可能地址的集合就称为虚拟地址空间。这个虚拟地址空间只是一个展现为机器级程序的概念性映像。

2.1.1 十六进制表示法

一个字节由8位组成,在二进制表示法中,他的值域是00000000~11111111.转化成10进制,值域是0到225。十进制和二进制对于描述位模式都不方便,于是以十六为基数,叫做十六进制数,来标示位模式。十六进制(简写为hex)使用数字0到9和字母a到f来表示16个可能的值。
在这里插入图片描述
在c语言中,以0x开头的数字常量被认为是十六进制的值。字符可以是大写也可以是小写,大小写混合写也可。
每四个二进制数对应一位十六进制数,当所给的二进制数位数不是4的倍数时要在最左边的一组前补0。

2.1.2 字数据大小

每台计算机都有一个字长,指明指针数据的标称大小。因为虚拟地址是以这样的一个字来编码的,所以字长决定的最重要的系统参数就是虚拟地址空间的最大大小。对于一个字长为W位的机器而言,虚拟地址的范围为0~2W-1,程序最多访问2的W次方个字节。
大多数64位机可以运行32位机编译的程序,这是一种向后兼容。
例:当程序prog.c用以下伪指令编译后
linux> gcc -m32 prog.c
该程序就可以在32位或64位机器上正确运行。
如果用以下伪指令编译
linux> gcc -m64 prog.c
那就只能在64位机器上运行。
因此,我们所说的程序位32位程序64位程序时,区别在于该程序是如何编译的,而不是其运行的机器类型。
在这里插入图片描述
程序员应该力图使它们的程序在不同的机器和编译器上可移植。可移植性的一个方面就是使程序对不同的数据类型的确切大小不敏感。C语言标准对不同数据类型的数字范围做了下界,但是却没有上界。

2.1.3 寻址和字节顺序

假设一个W位的整数,其位表示为[xw-1,xw-2,……x1,x0],如果w是8的倍数,那么其中最高有效字节包含[xw-1,xw-2,xw-3……,xw-8],而最低有效字节包含位[x7,……x0],其他字节包含中间的位。某些机器选择在内存中按照从最低有效字节到最高有效字节的顺序存储对象,而另一些机器则按照从最高有效字节到最低有效字节的顺序存储。前一种规则——最低有效字节在最前面的方式,称为小端法。后一种规则——最高有效字节在最前面的方式,称为大端法
假设变量x的类型为int,位于地址0x100处,他的十六进制值为0x1234567。地址范围0x100~0x103。
地址0x100~0x103的字节顺序依赖于机器的类型:
在这里插入图片描述
在C语言中,可以通过使用强制类型转换联合来允许以一种数据类型引用一个对象,而这种数据类型与创建这个对象时定义的数据类型不同。

2.1.4 表示字符串

c语言中字符串为一个以null(其值为0)字符结尾的字符串数组,每个字符都由某个标准编码来表示,最常见的是ASCⅡ字符码。十进制数x的ASCⅡ码正好是0x3x,而终止字节的十六进制表示为0x00。

2.1.5 表示代码

考虑下面c函数:

int sum(int x,unt y){
return x+y;
}

当我们在实例机器上编译时,生成如下字节表示的机器代码:
在这里插入图片描述
不同的机器类型使用不同的且不兼容的指令和编码方式。即使是完全一样的进程,运行在不同的操作系统上也会有不同的编码规则,因此二进制码是不兼容的。二进制码很少能在不同的机器和操作系统组合之间移植。

2.1.6 布尔代数简介

由来:布尔注意到通过将逻辑值TURE(真)和FALSE(假)编码为二进制值1和0,能够设计出一种代数,以研究逻辑推理的基本原则。下面是布尔运算符对应的逻辑运算符和在命题逻辑中的符号。

布尔运算名字逻辑运算符在命题中的符号真值描述
~NOT若p为真,则┐p为假
&合取AND只有当p,q都为真时,p∧q为真
析取OR只有当p,q为假是,p∨q为假
^异或EXCLUSIVE~ORp,q为真但不同时为真时,p⊕q为真

(因|(析取)与表格符号冲突无法在表格内显现,所以写在这里)
位向量:固定长度w、由0和1组成的串。位向量的运算可以定义成参数的每一个对应元素之间的运算。假设a和b分别表示位向量[aw-1,……a0]和[bw-1……b0]。那么a&b则表示为长度为w,第i个元素为ai&bi,(0<=i<w)的位向量。类似地|、^、~也可以这样写。
布尔运算&、|之间分配律成立。
当考虑长度为w的位向量上的^、&、和~运算时,会得到一种不同的数学形式,我们称为布尔环。
位向量一个很有用的应用就是表示有限集合。举个例子就懂了:
位向量a=[01101001]表示A={0,3,5,6}
因为a0是在右边的,从右往左看,第几位是1,就表示了第几位存在。
布尔运算的|和&分别表示集合里的并和交,而~表示补

2.1.7 C语言中的位级运算

C语言的一个很有用的特性就是它支持按位布尔运算。
以下是一些对char数据类型表达式求值的例子:
在这里插入图片描述
确定一个位级表达式的结果最好的方法,就是将十六进制的参数转换为二进制运算,然后再转回十六进制。
位级运算实现掩码运算,这里掩码是一个位模式,表示从一个字中选出的位的集合。
对于例子的解释:
例:掩码0xff(最低的8位为1)(这里的意思是低八位,置一,就是说低八位全是一,也就是0xff转换为二进制)
位级运算x&0xff生成一个由x的最低有效字节组成的值,其他字节全被置为0(想想&的计算法则)。
表达式~0可以生成一个全1的掩码,不管机器的字是多少。

2.1.9 C语言中的移位运算

C语言提供了一种移位运算,向左或者向右移动位模式。对于一个位表示为[xw-1,xw-2,……,x0]的操作数x,C表达式x<<k会生成一个值,其位表示为[xw-k-1,xw-k-2,……,x0,0,0,……0]。也就是弃掉最高的k位,并在右端补k个0。位移量应该是一个0~w-1之间的值。位移运算是从左至右可结合的,如x<<j<<k等价于(x<<j)<<k。
与左移运算对应的是右移运算,机器支持两种右移运算:逻辑右移和算术右移。逻辑右移在左端补上k个0,得到的结果是[0,……0,xw-1,xw-2,……,xk]。算数右移是在左端补k个最高有效位的值,得到的结果是[xw-1,…xw-1,xw-1,xw-2,…xk]。
看几个例子:
在这里插入图片描述
斜体的数字表示的是最右端(左移)或最左端(右移)填充的值。对算数右移[10010101]的解释是,因为最高位是1,所以填充的是1。
C语言没有明确定义对于有符号数应该使用哪种类型的右移。但对于无符号数,右移必须是逻辑的。
与C相比,java对于如何进行右移由明确的定义。表达式时x>>k会将x算数右移k个位置,而x>>>>k会对x做逻辑右移。
放上一个没看懂的旁注:
在这里插入图片描述

2.2 整数表示

2.2.1 整型数据类型

C语言支持多种整型数据类型——表示有限范围的整数。

在这里插入图片描述
在这里插入图片描述
C和C++都支持有符号(默认)和无符号数。Java只支持有符号数。

2.2.2 无符号数的编码

把向量x看作一个二进制表示的数,就获得了x的无符号表示。在这个编码中,每个位xi都取值为0或1,就一种取值意味着数值2i应为数字值的一部分。
定义:对向量x=[xw-1,…,x0]:
B2Uw(x)≐∑w-1i=0xi2i(注意≐不是=)
这个等式里,符号≐表示左边被定义为等于右边。函数B2Uw将一个长度为w的0、1串映射到非负整数。例:
在这里插入图片描述
就是二进制转十进制。
用数学原理简述其特性:
无符号数编码的唯一性。
函数B2Uw是一个双射。
数学术语双射是指函数的反函数也成立。
函数B2Uw将每一个长度为w的位向量都映射在0~2w-1之间的唯一一个值;反过来在0到2的w次方减一之间的每一个数都可以映射为一个唯一的长度为w的位模式。

2.2.3 补码编码

有符号数的计算机表示方式是补码形式
将字的最高位解释为负权。函数B2Tw可以表示
下面是函数演示:x=[xw-1,…,x0]:
B2Twx)≐-xw-12w-1+∑w-2i=02i
最高有效位xw-1也称符号位,它的“权重”为-2w-1,是无符号表示中权重的负数。符号位设置为1时,表示值为负,当设置为0时,值为非负。例:
在这里插入图片描述

针对不同字长,几个重要的位模式和数值。
在这里插入图片描述
注意几点:
一、补码的范围是不对称的,|TMin|=|TMax|+1,TMin没有与之对应的正数,这导致了补码的一些性质和容易造成的错误。
原因:以W=4为例,0x1000对应有符号数字是-23=-8
而0x0000对应的有符号数字是0;这导致正数比负数少了一个。

二、最大的无符号数值刚好比有符号数值的两倍大一点:UMaxw=2TMaxw+1。
C库中的文件<limist.h>定义了一组常量,来限定编译器运行的这台机器的不同整数数据类型的取值范围。

关于整数数据类型的取值范围和表示,Java标准是非常明确的。他要求采用补码形式表示,取值范围与2-10中64位情况完全一样。在Java中,单字节数据被称为byte而不是char。这些非常具体的要求都是为了保证无论在什么机器上运行,Java程序都能表显地完全一样。
有符号数的其他表示方法:
反码:在这里插入图片描述
原码:最高有效位是符号位,用来确定剩下的位应该取负还是取正在这里插入图片描述

2.2.4 有符号数和无符号数之间的转换

规则:数值可能会改变,但是位模式不变。
强制转换只是改变了解释位的方式,而不改变位模式。
更数学化的表示方式:
定义函数U2BwT2Bw,它们将数值映射为无符号和补码形式的位表示。给定0<=x<=UMaxw,函数U2Bw(x)会给出x的唯一的w位无符号表示i。
,当x满足TMinw<=x<=YMaxw,函数T2Bw(x)会给出x的唯一的w位补码表示。
现在定义函数在这里插入图片描述
这个函数的输入一介于TMinw到TMaxw的数,结果得到一个0到UMaxw的值(输入一个有符号的得到一个无符号的)
有一个性质:给定位模式w位对应的两个数值的绝对值之和等于2w
以w=4为例,负数转换为无符号数,值会增加16,因为最高有效位从-8变成了8。非负数不会改变。
无符号数u和有符号数U2Tw
对满足0<=u<=UMaxw的u有:
在这里插入图片描述
无符号数转换为补码:
在这里插入图片描述

2.2.5 c语言中的有符号数和无符号数

当进行逻辑运算时,算式中有一个数十无符号的数,另一个数也会被隐式转换为无符号数再进行比较,这就产生了一些“不直观”的结果例如:在这里插入图片描述
在这里插入图片描述在这里插入图片描述

2.2.6 扩展一个数字的位的表示

零扩展:将一个无符号数转换为一个更大的数据类型,在表示的开头添加0。
补码的符号扩展:将一个补码数转换为一个更大的数据类型,在表示的前面添加最高有效位的值。
值得一提的:从一个数据大小到另一个数据大小的转换,以及无符号和有符号数字之间的转换的相当顺序能够影响一个程序的行为(最后结果)例:在这里插入图片描述

2.2.7 截断数字

截断:大数变小数(减少表示一个数字的位数)
将一个w位的数截断为一个k位的数时,丢弃高w-k位。

2.3 整数运算

2.3.1 无符号加法

设两个非负整数x和y,满足0<=x,y<2w。每个数都可以表示为w位的无符号数。然而,计算它们的和,可能会得到一个范围为:0<=x+y<=2w-2的数。表示这个和可能需要w+1位来表示。
定义模运算:把整数x+y的结果截断为w位的数,即计算结果保留到w位,所有权重大于2w-1的位都丢弃,就可以计算出和模2w在这里插入图片描述
执行c程序时,结果溢出时不会报错,但是我们想知道是否发生了溢出,有如下方法:在这里插入图片描述
模数加法形成了一种数学结构,称为阿尔贝群,它是可交换和可结合的(这里没懂啥意思)。他有一个单位元0,并且每个元素有一个加法逆元。在这里插入图片描述

2.3.2 补码加法

与无符号数加法类似,在这里插入图片描述
推导过程没看懂
检测是否发生溢出在这里插入图片描述

2.3.3 补码的非

在这里插入图片描述
任何-x+x=0.

2.3.4 无符号乘法

范围在0到二的w次方减一的整数x和y可以表示为无符号数,它们的乘积在0到(2w-12=22w-2w-1+1之间,即可能需要2w位来表示,c语言定义无符号乘法产生w位的值。
在这里插入图片描述

2.3.5 补码乘法

在这里插入图片描述
说的是截断之后的位级表示一样。

2.3.6 乘以常数

计算机运算乘法速度相对较慢,编译器做了优化,试着用移位和加法运算的组合来代替乘以常数因子的乘法。
下面是乘以2的幂的情况:在这里插入图片描述
又,左移一个数值等价于执行一个与2的幂相乘的无符号乘法。
无论是无符号运算还是补码运算,乘以2的幂都可能导致溢出。但通过移位得到的结果是一样的。
对于乘法可以转换为:在这里插入图片描述
这两种形式进行计算。
对于选择使用移位以及加减的组合还是使用乘法指令取决于各指令的速度,而这些与机器的强度有关。

2.3.7 除以2的幂

整数除法要比整数乘法更慢,要30个或更多时钟周期,
整数除法同样可以用移位和加减法组合做运算,这里用的就是右移了。无符号和补码数分别用逻辑移位和算数移位。
偏置技术:在这里插入图片描述

2.4 浮点数

形如V=x*2y的有理数进行编码。它对涉及非常大的数字(|V|>>0)、非常接近于0(|V|<<1)的数字,以及更普遍地作为实数运算的近似值的计算。

2.4.1 二进制小数

十进制表示小数用如下格式:在这里插入图片描述
可以写成这样的公式:在这里插入图片描述
同理我们得出,二进制小数可以这样来表示:在这里插入图片描述
在这里插入图片描述
注意:形如0.1111111……12的数表示的刚好是小于1的数。我们用简单的表示法1.0-ε表示。
小数的二进制只能表示那些能够被写成x*2y的数。其他的数只能被近似表示。

2.4.2 IEEE浮点表示

IEEE浮点标准用V=(-1)sM2E的形式来表示一个数:

  • 符号:s 决定这个数是负数(s=1)还是正数(s=0),而对于数值0的符号位解释为特殊情况处理。
  • 尾数: M是一个二进制小数,它的范围是1~2-ε,或者是0到1-ε。
  • 阶码:E的作用是对浮点数加权,这个权重是2的E的次幂(可以是负数)。
    将浮点数的位表示划分为三个字段,分别对这些值进行编码:
  • 一个单独的符号位s直接编码符号s
  • k位的阶码字段 在这里插入图片描述
    编码阶码E。
  • n位小数字段在这里插入图片描述
    编码尾数M,但是编码出来的值也依赖于阶码字段是否为0。
    下图给出了这三个字段装进字中两种最常见的格式。单精度浮点格式(c语言的float)中s、exp和farc字段分别位1位、k=8位和n=32位,得到一个32位表示。双精度浮点数格式(c语言中的double)中,s、exp和frac字段分贝为1位、k=11
    位和n=52位,得到一个64位的表示。在这里插入图片描述
    给定位表示,根据exp的值,被编码的值可以分为三种不同的情况(最后一种情况有两个变种)。下图位单精度格式的情况:在这里插入图片描述
    看不懂在这里插入图片描述
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值