无符号(unsigned)编码基于传统的二进制表示法,表示大于或者等于零的数字;补码(two’s-complement)编码是表示有符号整数的最常见的方式,有符号整数就是可以为正或者负的数字;浮点数(floating-point)编码是表示实数的科学记数法的以二为基数的版本。
整数的表示虽然只能编码一个相对较小的数值范围,但是这种表示是精确的;而浮点数虽然可以编码一个较大的数值范围,但是这种表示只是近似的。
信息存储
计算机一般以8位为一个单位存储数据,我们称之为字节(byte),这是一个最小的可寻址的存储器单位。存储器的每个字节都由一个唯一的数字来标识,称为它的地址(address),所有可能地址的集合称为虚拟地址空间(virtual address space)。
十六进制与十进制的转换
如下:将十进制314156转换成十六进制,转换成十六进制之后是0X4CB2C。过程如下:
字与数据大小
每台计算机都有一个字长,指明整数与指针数据的标称大小。对于字长为w位的机器而言,虚拟地址的范围为0~2w-1,程序最多能访问2w个字节。下图为C语言各个数据类型的字节数。注意红框标出的数据类型。
字节顺序(大端小端)
不同的计算机,在计算机中存放方式并不一样。一种是最低有效字节在最前面,称之为小端模式(little endian);另外一种是最高有效位在最前面的方式,称之为大端模式(big endian)。具体如下图所示,对于十六进制数0X01234567,它存放的起始地址是0x100。
布尔代数
布尔代数就是我们在数电当中数据的真值表,有以下四种运算:
<1> ~对应于逻辑运算的NOT
<2> &对应于逻辑运算的AND
<3> |对应于逻辑运算OR
<3> ^对应于逻辑运算亦或(即相同的两个数为0,不一样的为1)
逻辑运算表如下:
布尔运算的那些符号放在C语言就叫做位级运算。
C语言中的逻辑运算
C语言提供三种逻辑运算符,分别是||、&&、!,分别对应于命题逻辑中的OR、AND、NOT,注意区别逻辑运算和位级运算,在逻辑运算中,运算的结果只有TRUE和FALSE,也就是对应于1和0两个数字;而位级运算对应的是每一位具体的值。位级运算(上图)与逻辑运算(下图)如下所示。
C语言中的移位运算
C语言中的移位运算分为逻辑移位和算数移位,都用x>>k(x<<k)这样的表达式。如果是逻辑右移,则左端补k个0,如果是算数右移,则左端补k个最高有效位的值。具体操作如下图。
注意图中的值,参数x是8位的,只是将两个值放在了一起。
还有在C语言中,对于无符号数据(也就是以限定词unsigned声明的整型数据),右移必须是逻辑的。而对于有符号数据(默认的声明的整型数据),算数或逻辑的都可以。
另外,对于Java的右移有明确的定义。表达式x>>k会将x算数右移k个位置,而x>>>k会对x做逻辑右移。
整数的表示
整型数据类型
C语言中支持多种整型数据类型,具体如下,分别在32位和64位机器上。
C与C++都支持有符号(默认)和无符号数,Java只支持有符号数。
无符号数的编码
CSAPP这本书中用到了很多函数,具体如下所示:
具体例子如下:
利用等比数列求和公式非常容易得到:
补码编码
所谓补码编码就是将一个十进制有符号数表示为二进制时,用它的补码表示。其中最高位是1,表示负数。我们的函数是B2Tw(Binar to Two’s-complement)来表示:
具体例子如下:
它的最小值为:
它的最大值为:
那么一个数的补码是怎么来的呢?
对于一个整数,比如1,它的二进制表示应该是00000001b,那么它的反码就是111111110b,如果仅仅用反码表示,0和255都会出现相同的编码,这个时候,我们利用反码+1,得到一种新的编码,也就是我们所说的补码,来表示有符号数中的负数。
有符号数和无符号数之间的转换
将有符号数转换成无符号数,公式如下:
无符号数转换成补码
扩展一个数字的位表示
将一个无符号数转换为一个更大的数据类型,我们只需要简单的在表示的开头添加0,这种运算叫做零扩展(zero extension)。将一个补码数字转换成一个更大的数据类型执行符号扩展(sign extension),规则是在表示中添加最高有效位的值的副本。如下所示:
整型运算
无符号加法
补码加法
补码非的求法
上面的方法就是先取反,然后+1;另外一种方法如下:注意红框中的数字是没有改变的,而其他位都取反了,也就是说一个二进制表示的数字,它的补码非就是它从最右边那个1及其后面的0都不改变,1左边的数取反。
乘以常数
除以2的幂
浮点数
二进制小数的求值
IEEE浮点表示
以上图为例,它的S是0,阶码E为4位,尾数M为3位,针对标注的1、2分别分析。
对于规格化2处,阶码值E=e-Bias,其中Bias=2k-1-1,其中k就是阶码的尾数,所以这里Bias=7,而e=0110b=6,所以E=-1,f=0.110b=6/8,M=f+1=14/8;
对于非规范化1处,阶码值E=1-Bias,其中Bias=2k-1-1,其中k就是阶码的尾数,所以这里Bias=7,所以E=-6,f=0.010b=2/8,M=f=2/8。