第二章 信息的表示和处理
§1 信息存储
一、十六进制表示法
十六进制中一个字节的值域为00H~FFH
用0x或0X开头表示十六进制数字常量
快捷算法:要表示的数字常量为x=2^n,n=i+4j,且0≤i≤3时,开头的十六进制数字为1(i=0)、2(i=1)、4(i=2)、8(i=3),后面跟随着j个十六进制的0。这里的j是代表着每四位二进制位对应的十六进制位,而i的范围是因为十六进制中每一位的范围是0-F
二、字
字长:指明整数和指针数据的标称大小。决定虚拟地址空间的最大大小
字长为w,虚拟地址范围为0~2^w-1,程序最多访问2^w个字节,cpu一次处理w位数据
三、数据大小
在不同字长的计算机中,相同的数据类型所占用的字节数不同
在64位机上生成32位代码:gcc -m32
四、寻址和字节顺序
多字节对象倍存储为连续的字节序列,对象的地址为所使用字节中最小的地址
字节顺序是网络编程的基础
1.两个通用规则(w为整数,位表示为[Xw-1,Xw-2,……,X1,X0],其中Xw-1是最高有效位,X0是最低有效位):
字节内部的顺序不变
反汇编器:确定可执行程序文件所表示的指令序列的工具;将可执行程序文件转换回可读性更好的ASCII码形式的程度
2.强制类型转换
五、表示字符串
c语言中字符串被编码成为一个以null(值为0)字符结尾的字符数组
命令man ascii:得到ASCII字符码表
六、表示代码
二进制代码在不同的操作系统上有不同的编码规则。所以二进制代码是不兼容的
七、布尔代数
1.最简单布尔代数:与& 或| 非~ 异或^(结果为0或1)
2.扩展的布尔运算:位向量的运算(结果仍是位向量)
位向量的应用:表示有限集合,对集合编码
八、位级运算
1.将位向量按位进行逻辑运算,结果仍是位向量
2.掩码运算
掩码:用来选择性的屏蔽信号,是一个位模式,表示从一个字中选出的位的集合。
用位向量给集合编码,通过指定掩码来有选择的屏蔽或者不屏蔽一些信号,某一位位置上为1时,表明信号i是有效的;0表示该信号被屏蔽。这个掩码就表示有效信号的集合。
0xFF:屏蔽除最低有效字节之外的所有字节。
~0:生成全1的掩码
九、逻辑运算
1.逻辑运算符:与&& 或|| 非!
2.计算方法:所有非零参数都代表TRUE,0参数代表FALSE。1代表TRUE,0代表FALSE
十、移位运算
1.左移<<
2.右移>>
逻辑右移:在左端补k个0,多用于无符号数移位运算
算术右移:在左端补k个最高有效位的值,多用于有符号数移位运算。
§2 整数表示
一、整型数据类型
整型数据类型——表示有限范围的整数
要用ISO C99中的“long long”类型,编译时要用 gcc -std=c99
二、无符号数编码
无符号数的二进制表示的一个重要性质:0-(2^w)-1中的每一个整数和长度为w的位向量是一一对应的
三、补码编码
补码的范围:-2^(w-1)~2^(w-1)-1
在可表示的取值范围内的每个数字都有一个唯一的w位的补码编码
补码的利用寄存器的长度是固定的特性简化数学运算
三、有符号数和无符号数之间的转换
强制类型转换:结果保持位值不变,只是改变了解释这些位的方式
函数U2T:从无符号数到补码;T2U:从补码到无符号数
四、C语言中的有符号数和无符号数
无符号常量:后缀字符U或u
1.转换原则:底层的位保持不变
(1)有符号数→无符号数
非负数——保持不变
负数——转换成大正数
(2)无符号数→有符号数
以2^*(w-1)为界限:
小于它——保持不变
大于它——转换为负数值
[0,2^(w-1))范围内的数字,无符号和补码表示相同;范围之外的,需要加上或者减去2^w
2.运算时若同时存在有符号数和无符号数,会隐式的将有符号数强制类型转换为无符号数,并且假设这两个数都是非负的。
六、扩展一个数字的位表示
扩展:从一个较小的数据类型转换为较大的数据类型,同时保持数值不变。
1.零扩展:在开头加上0。多用于无符号数转换为一个更大的数据类型。
2.符号扩展:添加最高有效位的副本。多用于补码数字转换
七、截断
截断:减少表示一个数字的位数。而这么做可能会改变它的值,这也是溢出的一种形式。
将一个w位的数截断为k位数字时,就会丢弃高w-k位。
八、总结
无符号数适用于没有任何数字意义的位的集合,比如地址;又或者实现模运算、多精度运算的时候,数字由字的数组表示的时候。
§3 整数运算
一、无符号加法(模运算)
等价于计算和mod2^w,直接丢弃x+y的w+1位表示的最高位
二、补码加法
本质:模掉w位的补码最高有效位的权重2的w次幂
结果:正溢出、正常、负溢出
三、补码的非
x=-2^(w-1)时,为-2^(w-1)
x>-2^(w-1)时,为-x
对每一位求补,再对结果+1
设k为最右面的1的位置,将k左边的所有位取反
四、无符号乘法
计算乘积模2
五、补码乘法
将2w位的乘积截断为w位。也就是说,需要mod 2的w次幂。
对于无符号和补码乘法来说,乘法运算的位级表示都是一样的
六、乘以常数
乘法指令很慢,而加法和移位相对较快。所以在编译器中,会使用移位和加法运算组合的方式来代替乘以常数因子
溢出不影响结果。
七、除以2的幂
除法比乘法更慢。当被除数为2的整数次幂时,通过右移来解决
无符号数除以2的k次幂,就等同于对其逻辑右移k位。
补码进行算术左移时,需要考虑补码数的正负,正数向下舍入到零,负数应该向上舍入到零。所以这里涉及到在移位前偏置,即:
x≥0时,直接将x算术右移k位
x<0时,先将x加上(2^k)-1,再算术右移k位
八、总结
计算机执行的“整数运算”实际上是一种模运算。
无论运算数是以无符号形式还是补码形式表示,都有完全一样或者非常类似的位级行为。
§4 浮点数
浮点表示对形如V=x X (2^y)的有理数进行编码,适用于非常大的数字、非常接近于0的数字或作为实数运算的近似值
不太关注精确;关注速度和简便性
一、二进制小数
将一个数表示为形如x/(2^k):将x的写成为二进制,并将二进制小数点插入从右边算起的第k个位置
二、IEEE浮点表示
1.IEEE浮点标准:
用V=(-1)^s*M*2^E来表示一个数:
符号:s决定这个数是正还是负。0的符号位特殊情况处理。
阶码:E对浮点数加权,权重是2的E次幂(可能为负数)
尾数:M是一个二进制小数,范围为1~2-ε或者0~1-ε(ε=1/2的n次幂
2. 编码规则:
单独符号位s编码符号s,占1位
k位的阶码字段exp编码阶码E
n位小数字段frac编码尾数M(同时需要依赖阶码字段的值是否为0)
3.两种精度
单精度(float),k=8位,n=23位,一共32位;
双精度(double),k=11位,n=52位,一共64位。
4.三种编码情况
即exp的位模式既不全0也不全1的时候,这是最一般最普遍的情况,因而是规格化的。
(1)阶码字段和阶码
这里是以偏置形式表示的有符号整数。
阶码E = e-Bias
Bias=[2^(k-1)-1]
(2)小数字段和尾数
二进制小数点在小数字段最高有效位的左边。
尾数M = 1+f(隐含的以1开头的表示)
即阶码域全为0时的数。
(1)阶码
阶码E = 1-Bias
(2)尾数
尾数M = f(小数字段的值,不包含隐含的1)
(3)非规格化的功能:
a. 提供了一种表示数值0的方法。
b. 表示那些非常接近零的数。逐渐溢出
特殊值是在阶码位全为1的时候出现的。分为两种情况:
(1)无穷:小数字段全为0
(2)NaN不是一个数
小数字段非0
一些运算的结果不能是实数或无穷的时候会返回这样的值。或者表示未初始化的数据。
三、舍入
舍入:找到和数值x最接近的匹配值x',可以用期望的浮点形式表示出来。
1.向偶舍入(默认方法)
即:将数字向上或向下舍入,是的结果的最低有效数字为偶数。(四舍六入,五求偶)
能用于二进制小数。
2.向零舍入
即:把整数向下舍入,负数向上舍入。
3.向下舍入
正数和负数都向下舍入。
4.向上舍入
正数和负数都向上舍入。
四、浮点运算
1.浮点加法
浮点加法是可交换的
浮点加法不具结合性
大多数值的浮点加法都有逆元,除了无穷和NaN。
浮点加法满足单调性
2.浮点乘法
浮点乘法是可交换的
浮点乘法不具有结核性
浮点乘法的单位元为1.0
浮点乘法在加法上不具备分配性
在一定条件下满足单调性
五、C语言中的浮点数
int → float 不会溢出但有可能舍入
int/float → double 结果保留精确数值
double → float 可能溢出为±∞,由于精确度较小也有可能被舍入
float/double → int 向零舍入,可能溢出。
遇到的问题:
1.书上28页的代码编译时出错
检查了代码好像也没什么错,不知道为什么……最后把那一行注释掉了就可以了……源代码如下
2.练习2.52没有怎么理解,希望老师上课能讲解一下