CS61C – 1 : 浮点数
前面比较基础,国内课程基本均有涉及。故笔记从浮点开始
(好吧我就是懒得记了) _(¦3」∠)_
这一部分对应的是第6小节的内容 (参考课程为 [Summer 20] ),重点围绕 IEEE 754 Standard 展开。
为什么引入浮点数?
计算机的数位总是有限的,但自然数是无限的
吾生也有涯,而学海无涯,后面忘了,殆已(
总之固定点数表示数字浪费位数且不灵活,而且单纯的优先位数对小数无能为力
浮点数原理
浮点数基于二进制下的科学计数法,即
$$ \pm 1.xxx\dots_2\times 2^{yyyy\dots} $$
易见上述表达式包含三个部分:
- 符号位(S):表示正负
- 指数(Exponent):2的幂次
- 尾数(Signaificand):小数部分
基于科学计数法, IEEE 754 对单精度浮点数的标准规定如下:
$$ |S(1\ bit)|Exponent(8\ bits)|Significand(23\ bits)| $$
对于指数位,此处标准使用了偏置表示法(Bias = 127),实际指数 = 储存值 – 127,所以计算公式为:
$$ Value = (-1)^S\times(1+Significand)\times 2^{Exponent – 127} $$
IEEE 还预留了特定指数和尾数的组合以表述特殊值
Exponent | Significand | Meaning |
0 | 0 | $\pm0$ |
0 | $\neq$0 | Denormalized(反规范化数) |
1~254 | any | Normal Number |
255 | 0 | $\pm\infty$ |
255 | $\neq$0 | NAN |
其中:
- NAN 表示无效操作,任何 NAN 参与的运算结果均为 NAN
- Denormals用于平滑地填充
0
和最小常规数之间的巨大间隙
突然下溢(Abrupt Underflow)和间隙(Gap)
前文提及在 IEEE 754 标准中,常规浮点数要求其二进制表示必须被归一化(Normalized),即尾数部分必须满足 1.xxx… 的形式(有一个隐含的前导1)。这使得所有常规数的绝对值都有一个下限,即最小的正常规数。而对于32为单精度浮点数,最小的正常规数为$a=1.0\dots 0_2\times2^{-126}2^{-126}=$,但第二小的正常规数却是$b=1.0\dots 01\times2^{-126}=(1+2^{-23})\times 2^{-126}= 2^{-126}+2^{-149}$
所以我们很容易的得到:
$$|0-a|=2^{-126}\gg|a-b|=2^{-149}$$
即在 0 和 a 之间存在一个巨大的“鸿沟”,也就是间隙;这个区间内的数字会直接被刷新为 0 ,也就是下溢。
Denormals的具体表示方法为:
- 指数域(Exponent Field) 全为 0
- 尾数域(Significand Field) 不为 0
- 不包含隐含的前导1。尾数就是 $0.xxx\dots$ 的形式
此时的计算公式为:
$$Value = (-1)^S\times (0.Significand)\times 2^{-126}$$
现在,最小的正数不再是 $2^{-126}$,而是: $min_{denormal} = 0.0…01_2 \times 2^{-126} = 2^{-23} * 2^{-126} = 2^{-149}$
这使得数值可以逐渐趋近于0而不是突然断开。因此,这个过程也称为 “渐进下溢(Gradual Underflow)”。
精度与准确性
精度(Precision):位数多少,表示细节能力
准确性(Accuracy):与真实值的接近程度
高精度$\neq$ 高准确性,例如:float pi = 3.14; 精度高但不准确
舍入模式
IEEE 754 定义了四种舍入模式:
Round toward $+\infty$ – 正无穷舍入
Round toward $-\infty$ – 负无穷舍入
Truncate – 向零舍入 以及 Round to nearest,ties to even – 向最近偶数舍入
浮点数运算
浮点数的运算是非结合的,因为大数会忽略小数,导致误差积累
类型转换
在大部分语言中强制类型转化可能会造成精度损失带来难以预料的bug
i == (int)((float)i) // Not always true
f == (float)((int)f) // Not always true either
其他格式
除单精度浮点数外,还有其他浮点形式,比如
- 双精度(double, binary64):1位符号 + 11位指数 + 52位尾数
- 半精度(fp16, binary16):1位符号 + 5位指数 + 10位尾数
- BFLOAT16:1位符号 + 8位指数 + 7位尾数(机器学习中很常见)
发表回复