核心内容
- 编码原则:无符号,补码,浮点
- 溢出(无符号、补码)、精度(浮点)
一、信息存储
- 字节:存储最小单元。程序的内存管理是在虚拟地址层面上。
- 字长:用于指明整数和指针数据的大小。编码虚拟地址,决定虚拟地址空间大小。
- 数据大小:编码数字的格式。其中long int 和指针的字节数是机器字长。(因为指针的值是地址,而地址长度即为机器字长)
char(1), short(2), int(4), long long int (8), float(4), double(8) - 多字节对象地址:最小的地址
字节顺序:大端(高位存储于低地址,自然的阅读方式)、小端(低位存储于低地址)。对于字符串则没有字节序之说。 - 位运算
(1)位向量:用于编码集合。因为位向量的布尔运算对应于集合运算。
(2)x=x^y,y=x^y, x=x^y (隐含的中间变量x^y,因为x^y配合x或y可以获得x,y的全部信息)
(3)掩码
set:&0, | 1;
get:&1, |0,^0;
oppose:^1;
(4)位移
算数、逻辑左移:低位补零
算数右移:高位补最高有效位的值——有符号整数
逻辑右移:高位补零——无符号整数
注:位移w很大时, 取k mod w,其中k为机器字长
二、整数的表示
- 有符号数:通常用补码表示,最高位为负权重;无符号数:用正常二进制表示
- 有符号和无符号的关系:——位表示不变
(1)可能会有相同的位表示
(2)强制类型转换时,位级存储(位表示)不变,只改变解释方式。
(3)有符号和无符号数转换:相差2^w
(4)一个运算数是有符号、另一个是无符号时,C语言隐式处理为无符号,会出现意想不到的错误,建议:不要使用无符号数。
(5)扩展
零扩展:无符号数
符号扩展:有符号数,前面扩展若干符号位。注:从高位起,连续若干个1可以等效成一个1,数值不变。
(6)截断:有可能改变数值,溢出的一种形式
无符号截断:直接mod2^k(k为截断后字长)
有符号截断:无符号截断+符号转换
三、整数运算
位级行为不变,满足结合律交换律和分配率
- 溢出的位级行为:正常运算 + 截断
- 无符号溢出相当于模运算,有符号溢出和无符号位级行为相同,解释结果不同。
- 无符号加法溢出:和小于加数
有符号加法负溢出:负变正,会截断;正溢出:正变负不会截断。 - 补码的非:位级表现为取反加1。数字上除Tmin的非是本身外,其它数的非即为相反数。
- 乘法的实现:位移(乘以2的幂次方)+加/减法
整数除法——除以2的幂(结果均为舍小数部分,留整数部分)
(1)无符号:逻辑右移,向下取整
(2)有符号:商为负数时,结果表现为向上取整。实现时:先偏置,再向下取整。
7. 算数溢出检测:加法——和小于加数;减法——加法检测逆过程,注意Tmin单独检测;乘法——用除法检测或利用截断和扩展,如下:long long unsigned c = a * b; unsigned d = (unsigned) c; if( d ! = c) Overflow;
- 容易出问题的地方:
(1)int和unsigned之间的转换
(2)正负不对称
(3)算数溢出
四、浮点数
- IEEE标准:符号、尾数、阶码
- 数值分布不均匀,靠近零的分布密
- 规格化、非规格化(接近于0)、特殊值(无穷、不定值)
- 浮点数和整数之间的对应关系和强制类型转化:
int->double or float->double:无影响
int->float:数字会被舍入
double->float:数字会溢出或舍入
float->int or double->int: 数字会向零舍入 - 浮点运算不具有结合性和分配性(可能溢出而丢失信息)