概述
引言
大家都知道,可以在计算机处理器直接运行的是由0,1构成的机器代码(machine code),本文将介绍浮点数(floating-point number )在机器码中是如何被编码表示的。
整数(integer)是如何被编码的呢?小伙伴们应该听过补码,原码,反码吧,这些正是整数被编码的不同规则。
原码:一定字长,在不溢出的情况下,最高位是符号位,跟上该整数二进制表示。符号位中0代表正数,1代表负数。
补码(two's compliment):最高位也是符号位,但是与原码不同的是符号位也参与到求值里。
例如:1001=-2^3+1=-7
而原码中 1001=-1
代表同一数值的原码是可以转换成其补码的。
很多文章里说补码是无法直接转换成十进制数值,要先换成原码再求,其实这是错误的。理解补码最高位也是参与值的即可。
后续笔者将会撰写一篇文章详细讲解原码,补码,以及反码。
下面开始正题吧!
浮点数(floating-point number)是什么
其实计算机表示小数有两种方式:
- 定点数 (fixed-point)
- 浮点数(floating-point)
区别在于,定点数编码小数时小数点位置是确定的,浮点数小数点位置是可以变化的。
如何用科学计数法来表示二进制小数,即形如:
V = ( − 1 ) s × M × 2 E V=(-1)^s times M times 2^E V=(−1)s×M×2E
0.25(d)可以写作
0.01 ( b ) × 2 0 0.01(b)times2^0 0.01(b)×20
也可以写作
1.0 ( b ) × 2 − 2 1.0(b)times 2^{-2} 1.0(b)×2−2
注:括号中的字母
d表示十进制 decimal
b表示二进制 binary
h表示十六进制 hexadecimal
IEEE floating-point representation
正如上文所述,IEEE是编码小数的一种标准。类比一下十进制的科学计数法,实际上也算一种标准,要写成形如
a
×
1
0
b
(
其
中
∣
a
∣
>
=
1
且
<
10
)
atimes10^b (其中|a|>=1且<10)
a×10b(其中∣a∣>=1且<10)
而二进制和十进制的区别只是基数不同,二进制也可以写成像科学计数法的形式。
而计算机正是用了这种方式。
IEEE表示数V,而V可以写成如下形式:
V
=
(
−
1
)
s
×
M
×
2
E
V=(-1)^s times M times 2^E
V=(−1)s×M×2E
已知数字特点,那么计算机只需要存取s,M,E即可。
s: sign ***占最高的一位***,可以看出是**符号位**,s=1表示负数(或0),s=0表示正数(或0)
M: significand **尾数**,二进制小数
E: exponent 对该数加权(可能是负数)
计算机常见字长有 32bit 64bit,因此IEEE规定了对应的两种不同位数的编码方式:
32位称为单精度
64位称为双精度
这些数就是想把 s,M,E 存起来。
最简单的方法就是直接全部转换成对应的二进制数,放到对应的位置上,显然IEEE不是这样。
如图,图中s编码s,exp编码E,frac编码M。这里的编码规则其实就是IEEE浮点数表示的核心了。
三种情况
设exp位有k位,frac有n位
Case 1(normalized values): exp位不全为0 且 不全为1
规定:
E=exp-Bias
Bias翻译为偏置量 且规定
B
i
a
s
=
2
k
−
1
−
1
Bias=2^{k-1}-1
Bias=2k−1−1
稍后分析Bias这样规定的原因。
根据位数和exp位的限定,我们可以推测出case1可表示的值范围。
由此图得知,E的范围比较对称,有一定负数,让浮点数中较小的值也可以编码。
M=1+ frac
由此可见,case1 无法表示0, 因为M永远大于等于1。
Case 2 (denormalized values):
exp位全部0
规定:
E=1-Bias(Bias=2^(k-1)-1)
M=frac
作用:
- 表示0 (+0与-0)。
- 表示一些非常接近于0的小数。
Case 3(special values):
exp位全部为1
当frac位不全为0时:
表示NaN(not a number) 比如根号下-1
当frac位全为0时:
如:k=3,n=2时
111100 011100 分别表示-∞与+∞
case | 正负 | E | M |
---|---|---|---|
case 1: exp位不全为0或1 | s=0为正,s=1为负 | E=exp-Bias | M=1+frac |
case 2:exp位全部是0 | s=0为正,s=1为负 | E=1-Bias | M=frac |
case 3:exp位全部是1 | frac=0,s=0表示正无穷,s=1为负无穷;frac!=0,均表示NaN | NA | NA |
特点
可以看出一定位数能表示的二进制浮点数是有限的。
当k=2,n=2时,让我们列出该情况下可以编码的所有数。
易知,bias=2^1-1=1
为了直观,V都化成了以4为分母的分数。
no. | bit | e | E | f | M | V |
---|---|---|---|---|---|---|
1 | 0 00 00 | 0 | 0 | 0 | 0 | 0 |
2 | 0 00 01 | 0 | 0 | 1/4 | 1/4 | 1/4 |
3 | 0 00 10 | 0 | 0 | 1/2 | 1/2 | 2/4 |
4 | 0 00 11 | 0 | 0 | 3/4 | 3/4 | 3/4 |
5 | 0 01 00 | 1 | 0 | 0 | 1.0 | 4/4 |
6 | 0 01 01 | 1 | 0 | 1/4 | 4/5 | 5/4 |
7 | 0 01 10 | 1 | 0 | 1/2 | 3/2 | 6/4 |
8 | 0 01 11 | 1 | 0 | 3/4 | 7/4 | 7/4 |
9 | 0 10 00 | 2 | 1 | 0 | 1 | 8/4 |
10 | 0 10 01 | 2 | 1 | 1/4 | 5/4 | 10/4 |
11 | 0 10 10 | 2 | 1 | 1/2 | 3/2 | 12/4 |
12 | 0 10 11 | 2 | 1 | 3/4 | 7/4 | 14/4 |
13 | 0 11 00 | - | - | - | - | +∞ |
14 | 0 11 01 | - | - | - | - | NaN |
16 | 0 11 10 | - | - | - | - | NaN |
17 | 0 11 11 | - | - | - | - | NaN |
其中
大家也可以自己列一下这个表,加深理解。
同时我们发现了从case 1到case 2的变化是非常均匀 的,V的变化量为1/16,这正是case2中 规定E=1-bias 的用意!!!
但是注意:后面V值变化并不均匀!!!
我们来讲两个例子。
-
0 00 10
可以其判断属于case 2(exp位都是0)
exp: 00(binary)=0(decimal)
E=1-bias=1-3=-2
frac: 0.10(b)=1/4(d)
M=f= 1/4(d)
V=2^(0)✖️1/4✖️2 ^(-2)=1/16 -
0 10 11
可以其判断属于case 1(exp位不都是1或者0)
exp: 10(b)=2(d)
E=exp-bias=2-3=-1
frac: 0.11(binary)=3/4(decimal)
M=1+f=7/4(d)
V=2^(0)✖️7/4✖️2 ^(-1)=14/16
V与IEEE表示的相互转换
IEEE位格式(bit representation)到V
上文在讲例子时,已经介绍了从位格式求V值。
步骤:
- 根据exp位判断属于哪个case
- 写出s,exp,frac 根据不同规则求出E,M
- 代入公式
V = ( − 1 ) s × M × 2 E V=(-1)^s times M times 2^E V=(−1)s×M×2E
V转换成IEEE位格式
步骤:
- 明确单精度还是双精度。顺势求出bias值
单精度: s 1位, exp 8位, frac 13位,bias=127
双精度: s 1位, exp 11位,frac 52位,bias=1023 - 判断是case 1 还是case 2(case3 的情况只有+∞和NaN)
Bit representation很好看出 exp。
这种情况也不难,判断一个范围即可,求出case 1能表示的最大值(正数为例)。
单精度:
1 00000000 1111111111111
exp=0
E=1-bias-1-127=-126
frac=0.1111111111111(b)=0.9998779296875
M=0.9998779296875
V=2^(-126)✖️0.999877929687
约等于
1.17535
×
1
0
−
38
1.17535times 10^{-38}
1.17535×10−38
若V比此值小,则是case 1。否则是case 2。
双精度
该值约等于
2.22507
×
1
0
−
308
2.22507times 10^{-308}
2.22507×10−308
- 将V值转换成二进制(只考虑能确切转换成二进制的情况),并化成标准型
形如
V = ( − 1 ) s × M × 2 E V=(-1)^s times M times 2^E V=(−1)s×M×2E
注意:
case 1, 用E来加权,调整M到位数1.xxxxxxx
case 2, 用E来加权,调整M到位数0.xxxxxxx
举例:
单精度下,V=12345.0(d)
解:显然属于case 1
12345.0(d)=11000000111001
化标准型
V
=
2
0
×
1.1000000111001
×
2
13
V=2^{0}times1.1000000111001times 2^{13}
V=20×1.1000000111001×213
则 s=0
frac=10000001110010000000000 【13位,少了还得在后面补0,凑成23位】
E=13
exp=E+bias=13+127=140=10001100(b)【恰好8位,少了在前面补0】
则位表达为
01000110010000001110010000000000
0 1000110010000001110010000000000
01000110010000001110010000000000
舍入问题 (Rounding)
“Floating-point arithmetic can only approximate real arithmetic, since the representation has limited range and precision. Thus, for a value x, we generally want a systematic method of finding the ‘closest’ value.”
“The IEEE floating-point format defines four different rounding modes. The default method finds a closest match, while the other three can be used for computing upper and lower bounds”
其中说的默认方法是round-to-even,它和传统的四舍五入的唯一区别就是对中值的处理。
四舍五入,顾名思义,五永远是要进位的。
而round-to-even,五的话要round到最近的偶数值。
比如:1.5 四舍五入后 2
1.5 round-to-even 2
2.5 四舍五入后 3
2.5 round-to- even 2
优势:
在统计时,若采用四舍五入,那么数据值总是偏大一些,而round-to-even方法在中值处舍和入的概率都是0.5,数据值较为准确。
mode | 1.4 | 1.6 | 1.5 | 2.5 | -1.5 |
---|---|---|---|---|---|
四舍五入 | 1 | 2 | 2 | 3 | -2 |
round-to-even | 1 | 2 | 2 | 2 | -2 |
round-toward-zero | 1 | 1 | 1 | 2 | -1 |
round-down | 1 | 1 | 1 | 2 | -2 |
round-up | 2 | 2 | 2 | 3 | -1 |
round-toward-zero 模式就是在向0舍入。
round- down就是向数轴负方向舍。
round-up就是向数轴正方向入。
补充:
- round-to- even在保留一定位小数时也可以用到。
比如:1.2350和1.2450保留2位小数。用round-to-even mode后都是1.24 - 二进制也可以用round-to-even
0为even(偶数),1为odd(奇数)
比如:保留2位小数。
10.00011 (b)应该为 10.00(b) 而 10.00110(b)应该为10.01(b)。这两个数都不是中值。
举两个中值(请体会这里中值的含义,是对于保留2位小数而言的)的例子吧!
10.001(b)应该舍为 10.00(b)
10.111(b)应该进入为11.00(b)
注意:都是让小数舍入后最低位为even,即0
二进制小数舍入(Round-to-even)例题:
保留一位小数
before | 与中值的关系 | after |
---|---|---|
10.011 | 大于中值,要入 | 10.1 |
10.010 | 等于中值,要round-to-even(0) | 10.0 |
10.110 | 等于中值,要round-to-even(0) | 11.0 |
11.001 | 小于中值,要舍 | 11.0 |
关于中值:
10.0xx保留一位小数,其中值为10.010,准确的说,10.010是10.0(舍后的值)与10.1(入后的值)的中值。
类比1.5是1(舍后的值)和2(入后的值)的中值。
参考资料:Computer Systems: A Programmer’s Perspective 3rd edition
亲爱的读者们,欢迎指正错误和提问。
最后
以上就是飘逸玫瑰为你收集整理的如何深刻理解IEEE浮点数的表示(IEEE floating-point representation)舍入问题 (Rounding)的全部内容,希望文章能够帮你解决如何深刻理解IEEE浮点数的表示(IEEE floating-point representation)舍入问题 (Rounding)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复