计算机基础补完计划 - 自学计算机科学相关课程。此部分为深入理解计算机系统及相关视频课程的学习笔记。此部分主要讲解整数和浮点数在计算机系统中的表示。
1. Binary encoding
MASK:用于和二进制串组合运算,得到其中一部分。
[原码,反码,补码的相关内容,略]
补码的另一种解释,把符号位作为负的二进制表示,例如四位二进制数: $$ 0_{10} -1_{10} = 1111_{2} =-1 * 2 ^{3} + 1 * {2} ^ 2+12^{1}+12^{0} $$
2. Integers in C
limits.h
文件提供了有符号和无符号数的边界等宏定义。
在C语言中,无符号数占优,即表达式中混合使用无符号和有符号数时,有符号数会被转换为无符号数。
3. Bit shifting and sign extension
基于移位操作符,扩展有符号数。
在不产生溢出的情况下,逻辑移位(补0)等同于无符号数的乘2和四舍五入的除法,数学移位(Arithmetic shift,补最高位),等同于有符号数的乘除。
移位和掩码结合使用,可以提供丰富的位操作,如获取特定部分比特位等。
用位运算可以替换一部分条件语句,例如:
// 写法1
if(x)
a = y;
else
a = z;
// 写法2-三目运算符
a = x?y:z;
// 写法3:使用位运算
a = ((x<<31)>>31) & y + ((!x<<31)>>31) & z;
在优化的相关文章中提到:
现代的CPU有指令预测的功能,加入条件语句后会削弱指令预测的效果,因此第三种写法在某些情况下能够提高性能。
4. Fractional binary number
[二进制小数的内容,略]
二进制小数的问题在于只能精确表示由2的幂次组成的小数,其他的有理数(Rational number)只能通过循环二进制小数来表示。
Fixed Point Representation,固定小数点的位置来用二进制数表示小数,首先不够灵活,其次范围有限(数字表示的范围、精度难以界定和统一,这些受到小数点位置的影响)。
因此选择了Floating Point number。
5. Floating point
[C语言中的浮点数表示法,略]
来自IEEE浮点表示规范:IEEE Standard 754,这一规范主要考虑数学需求(Driven by numerical concerns),设计用来处理四舍五入、溢出和下溢(Standards for handling rounding, overflow, underflow),难以用硬件适配但数学上表现良好(Hard to make fast in hardware but numerically well-behaved)。
浮点数的数学形式: $$ V_{10}=(-1)^{s}M2^{E} $$
S为符号位;M为[1.0,2.0)之间的有效位数(尾数,不含整数部分);指数E。
单精度浮点数占4字节,S、E、M分别占1bit,8bit,23bit;双精度浮点数占8字节,S、E、M分别占1、11、52bit。
实际存储中,M不包含整数部分,E用exp-Bias
表示,即k bit的E,其1-(2k-2)分别表示的是(2-2k-1)-(2k-1-1),此时的E全零或者全1保留用(表示无限或0)。
6. Floating point operations and rounding
$$ x+_{f}y=Round(x+y)\
x*_{f}y=Round(x+y) $$
浮点计算,首先会计算精确值,然后将其近似到满足精确度要求的位数上,此时可能会有两种意外情况出现:指数过大以至于溢出;小数部分过小被省去(以至于损失精度)。
近似有朝0、朝(上)正无穷、(下)负无穷、最近、平均等方式。但是一直朝着同一个方向近似,会引入统计偏差。因此IEEE标准规定采用平均近似(Round-to-even),即一半向上近似,一半向下近似 。
浮点数的实现使得其不一定满足分配律和结合律。
7. Floating-point in C
C语言提供了32bit和64bit的浮点表示标准,分别记为float和double,定义在math.h中。
值得注意的是,这样表示的浮点数进行是否相等的比较时是不精确的,结合律和分配律也不一定适用,因此使用浮点数进行运算时需要格外注意。
在int、float、double之间进行类型转换时,会有以下情况:
int ->float:
一定不会溢出,但是可能会损失尾数;
int -> double或者float -> double:
只要int小于等于53bit字长,就不会有精度损失
double/float -> int:
尾数部分被截断(朝0舍入)
超出表示范围或NaN时,一般会被设为Tmin(最小值)