本次笔记内容:
04.浮点数的计算机表示
在1985年建立,如下表。
2^i | 2^{i-1} | … | 4 | 2 | 1 | |||||
---|---|---|---|---|---|---|---|---|---|---|
b_i | b_{i-1} | … | b_2 | b_1 | b_0 | b_{-1} | b_{-2} | b_{-3} | … | b_{-j} |
1/2 | 1/4 | 1/8 | … | 2^{-j} |
可以看出,其二进制表示方式为 ∑ k = − j i b k ⋅ 2 k \sum^i_{k=-j} b_k \cdot 2^k ∑k=−jibk⋅2k。
下例中,“-”代表又。
可以看出,存在局限性:
只能精确地表示X/2^k这类形式的数据,而对于下列数据,不能精确表示:
数字形式: ( − 1 ) s M 2 E (-1)^s M 2^E (−1)sM2E
编码形式:
exp域:E(注意,E要进行变换,再存储在exp中);
frac域:M。
Float F = 15213.0; // 二进制 15213_10 = 11101101101101_2 // 二进制向右移13位,再乘2^13 1.1101101101101_2 * 2^13 // 则其尾数为 M = 1.1101101101101_2 // 取小数部分,在计算机中存储为 frac = 11011011011010000000000 // 其阶码为 E = 13 Bias = 127 // 阶码在计算机中存储为,加上偏置量 Exp = 140 = 10001100
最终,15213.0在计算机中的存储为(第二行):
Hex | 4 | 6 | 6 | D | B | 4 | 0 | 0 |
---|---|---|---|---|---|---|---|---|
Binary | 0100 | 0110 | 0110 | 1101 | 1011 | 0100 | 0000 | 0000 |
140 | _100 | 0110 | 0____ | |||||
15213 | (1)110 | 1101 | 1011 | 01__ |
上表中,M取值一定位1.x,因此15213行的首个1省略。
为什么Bias取2^{e-1} - 1(e = exp的域的位数)?或者说,为什么在规格化浮点数情况下不允许exp取全0?
答:在不考虑符号位的情况下,考虑规格化浮点数的最小取值:首先E应该取1(exp为1减去偏移量即1-Bias),frac取1.0…。如果有数字,比这个数还小一点点,则只能将frac小数点再左移。此时,则需要exp全0这种表达,表示此时frac是0.开头,而非1.开头。0.开头即非规格化浮点数。
取值范围如下表。
s | exp | frac | E | value |
---|---|---|---|---|
0 | 0000 | 000 | -6 | 0 |
0 | 0000 | 001 | -6 | 1/8 * 1/64 = 1/512 |
0 | 0000 | 010 | -6 | 2/8 * 1/64 = 2/512 |
… | ||||
0 | 0000 | 110 | -6 | 6/8 * 1/64 = 6/512 |
0 | 0000 | 111 | -6 | 7/8 * 1/64 = 7/512 |
0 | 0001 | 000 | -6 | 8/8 * 1/64 = 8/512 |
0 | 0001 | 001 | -6 | 9/8 * 1/64 = 9/512 |
… | ||||
0 | 0110 | 110 | -1 | 14/8 * 1/2 = 14/16 |
0 | 0110 | 111 | -1 | 15/8 * 1/2 = 15/16 |
0 | 0111 | 000 | 0 | 8/8 * 1 = 1 |
0 | 0111 | 001 | 0 | 9/8 * 1 = 9/8 |
0 | 0111 | 010 | 0 | 10/8 * 1 = 10/8 |
… | ||||
0 | 1110 | 110 | 7 | 14/8 * 128 = 224 |
0 | 1110 | 111 | 7 | 15/8 * 128 = 240 |
0 | 1111 | 000 | n/a | inf |
可以看出,在不考虑符号位s时,较好通过浮点数二进制表示方式比较大小。
其他情况都可以直接使用无符号整数的比较方式:
基本流程:
1.40 | 1.60 | 1.50 | 2.50 | -1.50 | |
---|---|---|---|---|---|
Zero | 1 | 1 | 1 | 2 | -1 |
Round down | 1 | 1 | 1 | 2 | -2 |
Round up | 2 | 2 | 2 | 3 | -1 |
Nearest Even(default) | 1 | 2 | 2 | 2 | -2 |
Nearest Even为向最近的偶数舍入(并非四舍五入)。是计算机内默认的舍入方式。
这是计算机内默认的舍入方式,也称为“(将0.5)向最接近值的舍入”。
关键的设计决策的是确定两个可能结果的中间数值的舍入,确保舍入后的最低有效数字是偶数。
E.g., round to nearest hundredth
1.2349999 | 1.23 | (Less than half way) |
---|---|---|
1.2350001 | 1.24 | (Greater than half way) |
1.2350000 | 1.24 | (Half way - round up) |
1.2450000 | 1.24 | (Half way - round down) |
实例如下表,舍入到小数点后2位:
Value | Binary | Rounded | Action | Rounded Value |
---|---|---|---|---|
2 3/32 | 10.00 011 | 10.00 | (<1/2 - down) | 2 |
2 3/16 | 10.00 110 | 10.01 | (>1/2 - up) | 2 1/4 |
2 7/8 | 10.11 100 | 11.00 | (1/2 - up) | 3 |
2 5/8 | 10.10 100 | 10.10 | (1/2 - down) | 2 1/2 |
可以看出,“Even”意味着如下规则:
将8位无符号数转换为8位浮点数(exp域宽度为4 bits,frac域宽度为3 bits)
首先,规格化:
Value | Binary | Fraction | Exponent |
---|---|---|---|
128 | 10000000 | 1.0000000 | 7 |
15 | 00001101 | 1.1010000 | 3 |
17 | 00010001 | 1.0001000 | 4 |
19 | 00010011 | 1.0011000 | 4 |
138 | 10001010 | 1.0001010 | 7 |
63 | 00111111 | 1.1111100 | 5 |
接下来,舍入:
Value | Fraction | Incr? | Rounded |
---|---|---|---|
128 | 1.000 0000 | N | 1.000 |
15 | 1.101 0000 | N | 1.101 |
17 | 1.000 1000 | N | 1.000 |
19 | 1.001 1000 | Y | 1.010 |
138 | 1.000 1010 | Y | 1.001 |
63 | 1.111 1100 | Y | 10.000 |
其中,17、19由于是舍去1+0*,因此要求Rounded之后以0结尾。
最后,调整:
Value | Rounded | E | Adjusted | Result |
---|---|---|---|---|
128 | 1.000 | 7 | 128 | |
15 | 1.101 | 3 | 15 | |
17 | 1.000 | 4 | 16 | |
19 | 1.010 | 4 | 20 | |
138 | 1.001 | 7 | 134 | |
63 | 10.000 | 5 | to 1.000, E = 6 | 64 |
当int(32位宽),float,与double等类型间进行转换时,基本的原则如下:
以下判断是否成立,如果不成立请给出反例。
int x = foo(); float f = bar(); double d = foobar();
假设d与f都不是NaN。
不成立,float有效位数不够。
成立。
成立。
不成立。
成立。
不成立。
因为2/3是整数运算,等于0,而右侧是浮点数运算。
成立。因为浮点数是逐渐丧失精度,可以变成负无穷。
成立。
成立。不存在有符号整数突变为负数的情况。
不成立。由于f的精度低,因此,d+f时f容易被忽略。
给定一个浮点格式,有k位指数和n位小数,对于下列数,写出阶码E、尾数M、小数f和值V的公式。另外,请描述其位表示。
B i a s = 2 k − 1 − 1 Bias = 2^{k-1} - 1 Bias=2k−1−1
E = e x p − B i a s E = exp - Bias E=exp−Bias
V = ( − 1 ) s M 2 E V = (-1)^s M 2^E V=(−1)sM2E
E最大值为 2 k − 1 − ( 2 k − 1 − 1 ) = 2 k − 1 2^k - 1 - (2^{k-1} - 1) = 2^{k-1} 2k−1−(2k−1−1)=2k−1。
5.0 // 转换为二进制 ==> 101 // 进位,直到取最左1 ==> M = 1.01 // 此时,E = 2 frac= 01 0* // 共n位 exp = E + Bias = 2 + (2^(k-1) - 1)
则,位的描述为:
s | exp | frac |
---|---|---|
0 | bin(2 + 2^(k-1) - 1) | 01 0000…(共n位, 开头为01, 0补其他位) |
参考上文实例:一种“小”浮点数中的表格,思路如下:
frac有n位,则M可视为 1 + 1 2 n × C 1+\frac{1}{2^n} \times C 1+2n1×C;
其中,C是整数,由frac决定,即 C = o c t ( f r a c ) C=oct(frac) C=oct(frac);
并且C满足 0 ≤ C ≤ 2 n − 1 0 \le C \le 2^n - 1 0≤C≤2n−1。
默认V为正数(即s=0),则可将V表示为:
V = ( 1 + 1 2 n × C ) × 2 E = 2 E + 2 E − n × C V=(1+\frac{1}{2^n} \times C) \times 2^E = 2^E + 2^{E-n} \times C V=(1+2n1×C)×2E=2E+2E−n×C
则现在的任务有两个:
下面分类讨论:
情况一:E可以取到n时,
即 2 k − 1 ≥ n 2^{k-1} \ge n 2k−1≥n时,
E取n,C取其能取的最大奇数,即1* 01(保证最右两位是01, 其他位为1)。
情况二:E*取不到n时,
即 2 k − 1 ≤ n 2^{k-1} \le n 2k−1≤n时(不太可能),
E取最大即 2 k − 1 2^{k-1} 2k−1,而C取 2 n − E 2^{n-E} 2n−E(为了约掉后一项小数)。
exp为0* 1,frac为0*。
E取最小,即 e x p m i n − B i a s = 2 0 − ( 2 k − 1 − 1 ) exp_{min} - Bias = 2^0 - (2^{k-1} - 1) expmin−Bias=20−(2k−1−1)。
十进制即为 1 × 2 ( 2 0 − ( 2 k − 1 − 1 ) ) = 2 2 − 2 k − 1 1 \times 2^{(2^0 - (2^{k-1} - 1))} = 2^{2 - 2^{k-1}} 1×2(20−(2k−1−1))=22−2k−1。