浮点数:表示更大范围的小数(#)
浮点数:表示更大范围的小数(#)使用定点法来保存小数并不是最优秀的方案,不比整数,保存小数需要考虑到两个维度:精度和范围。
提高精度只能通过不断地扩充位数来实现;而定点数可以表示的取值范围十分有限(见上一节最后的栗子)。
浮点数的发明,正是为了解决取值范围的这个问题。
大家应该都知道科学计数法吧(百科:科学计数法),IEEE 浮点数表示方式跟科学计数法有些相似,但更为复杂。
IEEE 浮点标准用的形式来表示一个数。
组成部分依次是“符号 * 尾数 *阶码”:
[*]符号(sign)决定这个数是正数(s = 0)还是负数(s = 1);
[*]尾数(significand)决定这个数的精度,这里是用定点法表示;
[*]阶码(exponent)决定这个数的范围,它是一个加权值,权重自然是 2 的 E 次幂。
下边小甲鱼给大家列举出 C 语言中对 float 和 double 的封装格式:
可见,float 的三个字段分别是分配 1 位,8 位和 23 位;而 double 则是分配 1 位,11 位和 52 位。
当然,这里并不是直接用二进制表示各个字段的值,要不小甲鱼就不用写这篇文章了……
{:9_237:}
根据阶码(exponent)的值,上述编码还需要被解释成 4 种不同的情况(下边以 float 举例):
1. 规格化的值
2. 非规格化的值
3. 无穷大
4. NaN(Not a Number,不是一个数)
OK,下边小甲鱼给大家逐一介绍:
1:规格化的值
这是最普遍的情况,当 exp 字段不全为 0,也不全为 1 的时候,属于这种情况。
在这种情况下,阶码字段被解释为以偏置(biased)形式表示的有符号整数。
{:9_229:}
呃……说人话就是你只需要记住公式:E = e - Bias
其中,e 是一个无符号数,其值为 exp 字段表示的值;Bias 是一个等于 (k 即阶码字段的位数)的偏置值。
由此不难推导出指数 E 的取值范围是 -126 ~ 127(float)和 -1022 ~ 1023(double)。
对于 frac 字段则被解释为描述小数的值,如果我们把该值称之为 f,则 0 <= f < 1,而尾数被定义为 M = 1 + f
因此,在这种情况下,尾数的第一位总是 1。
2:非规格化的值
当 exp 字段全为 0 的时候,所表示的数就是非规格化形式。
在这种情况下,阶码的值是 E = 1 - Bias
而尾数被定义为 M = f
因此,在这种情况下,尾数即小数的值(第一位不是 1)。
非规格化数用于表示那些非常接近 0.0 的数。
3. 无穷大
当 exp 字段全为 1,且 frac 字段全为 0 的情况下,该浮点数表示无穷。
即 s = 0,结果为正无穷;s = 1,结果为负无穷。
当我们把两个非常大的数相乘,或者除以 0 的时候,无穷能够表示溢出的结果。
4. NaN
在第 3 种情况的基础上,frac 即小数域为非 0 时,我们把结果称之为 NaN,即 Not a Number(不是一个数)。
一些运算的结果不能是实数或无穷来表示,就会返回这样的 NaN 值。
小甲鱼知道大家现在肯定云里雾里的,下边举几个栗子吧!
{:9_227:}
某天,小甲鱼在内存中捡到一个 float 变量,存储如下:
分析:
1. 符号位为 0,说明这丫是一个正数;
2. exp 字段不全为 0 或 1,表示这是一个规格化的值。根据公式 E = e - Bias,求得 E = 124 - 127 = -3;
3. frac 字段的值为 3/4(这里是定点数表示法,忘了的鱼油请回顾上一篇),则 M = 1 + 3/4 = 7/4
4. 根据浮点数公式,求得:
其实也是很简单的,对吧?!
{:9_223:}
回复“朕想知道”,给你看一篇文章 —— 浮点溢出的高昂代价
**** Hidden Message *****
本文参考:《深入理解计算机系统》P70 ~ 72
看看 朕知道了 顶起来~~~~~~~~~~~~~ 11 float的三个字段位分别是是1位,8位和23位? 已经晕了 联想知道 郑想知道 刚好在看这本书。正看的发晕呢 想知道 :call: 郑想知道,
好难啊!!
1{:9_238:} 朕想知道 学习一下浮点数 真想知道 朕想知道
:dizzy: 朕想知道 上面“1位,8位,23位”编辑错了{:5_91:}