由于关于实型数介绍的资料很少,同时介绍的资料描述得都很简短,各种专业教程中都是
简单带过,没有具体的讲解.这样的情况下只好边参考资料边进行逆向分析,经过分析验证后
得出以下结论并整理成文档。虽然编写程序时可以不关心它的存储方式,编译器可以自动进
行转换,但在许多情况下了解它的存储方式却是个关键。以下的分析目的都旨在于:
"知其然,知其所以然".
读懂本文所需的前提是了解[补码]
实型数的表示,根据IEEE(14)标准分析如下
一.先将浮点数转换为二进制数并进行规格化.
1.转换为二进制并规格化一个数时将其调整为大于等于1而小于2,存储时隐含掉整数部分只保留尾数;
如(这部分可以只了解下):
10进制数12
10进制转2进制为: 12 = 1100 ;
1100 规格化后为: 1.1 * 2^3这样一个表达式(等同于对1.1左移位3次),2^3 表示2的3次方.
12 : 是正数既符号位为0. 存到符号字段中
2^3: 3就是阶码. 存到阶码字段中
1.1: .1是尾数. 存到尾数字段中
"1.1"中的整数"1"不需要存储,只存储尾数
如果是0.111这样的二进制数码则调整为 1.11 * 2^-1 .
即阶码 = -1;
尾数 = 11;
数值"12"存储为float的结果是:
(数据结构图)
为了对齐行列,各表示: A:符号; B:移码阶; C:尾数.
| A | B | C |
| 0 | 10000010 | 1000000 00000000 00000000 |
关于B:移码阶部分一定会让人比较迷惑,这里可以先不用管,这部分重点放在第二大段中介绍.
2.浮点数中尾数的二进制转换及规格化
浮点数尾数部分。
通常的转换方式可以转换得出(如除2求余法),但进一步整理下思路可以使后文
更易于理解.
以10进制数:27.4375为例,它们的关系是(书上直接抄来的例子):
A冥 B权 C数码 D数值(10进制)
A 2^4 2^3 2^2 2^1 2^0 2^-1 2^-2 2^-3 2^-4
B 16 8 4 2 1 0.5 0.25 0.125 0.0625
C 1 1 0 1 1 . 0 1 1 1 11011.0111(2进制)
D 16 + 8 + 0 + 2 + 1 + 0 + 0.25 + 0.125 + 0.0625 = 27.4375
二.在机器中的存储方式
以float来做分析,存储中位的顺序由高到低描述是:
float 符号位1bit;阶码位8bit;尾数23bit.共计32bit 即 4 byte长度.
符号位:
标识数的正负符号,1表示(-)
阶码部分:
由于是8bit;阶为2。因此2的8次方 = 256个描述信息
规范中,数的表示法有些特别,使用偏移量方式计算。
表示方法为: 阶的偏移量 E_Disp = 127 = (256/2 -1)
阶码为E表示为 存储方式[e] = E + E_Disp
所以,使用存储方式[e]来计算时需要在之上减去E_Disp,
即: E = [e] - E_Disp
此阶码的特点:
这种表示法形式实为补码,但这种表示法不同于普通补码.它使用偏移量计算,
偏移量即补码,同普通补码的区别是末位不进行加1修正.
这种表示法中因为0不应该存在负数,而又没有普通补码表示法的修正,所以
存储0时全存为0
同时这样的方法带来一个额外的空间,原因是表示 (+-)127 的情况下范围
为:127*2 = 254 实际可用范围为256,0占用1个范围,(+-)127占用254的范围,这
样就是:256-(127*2 + 1) = 1。但是这个描述信息并没有被浪费,它在IEEE(14)
2 自学者疑难之一,实型数在计算机中的存储方式
规范中用于表示无穷大即:∞。这种方式下无穷表示为:阶码部分全为1,尾码部分
全为0,符号位标识 (+- ∞).
综合说明:
1.阶码存储为: 阶码 + 偏移量127;
2.被存储的数值为0时不进行任何形式的转换,将其全存为0,符号位唯一确定为0;
3.被存储的数值为+-无穷时阶码位全存为1,尾数位全存为0,符号位表示+-;
尾数部分:
可以倒回去看第一大段的例子.
额外的说明与思考:
这种形式是一种科学标识法其起源很早,但鄙人才疏学浅无从追寻根源,这种形
式只为此方式的一种。进一步了解该方法是将来解决许多问题的捷径写出能解决特殊
问题的算法的基础。后面紧接着就更深入的分析下去。
已提到这是一种科学标识方法,它并不局限于IEEE标准,它的实际形式是:
|符号位|阶码符号位|阶码|尾数|
这个形式在 "阶码"和"尾数" 的长度上并没有数理上的限制,特殊场合里可以进行
自定义.这里不是说在编写程序的时候可以不理会IEEE的标准了,那取决于当前的开发
环境,在机器上使用标准开发环境时是必须严格遵守IEEE标准的,这是一个规范,否则就
要放弃环境的默认处理,改为自己用算法来处理数的转换及计算.
也就是说如果使用了自己定义的数据,那如cpu 的 ADD 指令等不能再直接使用来进
行对它的处理了,因为计算机的数据格式是遵循IEEE标准的.这段话看起来有点让人觉得
废话,但我觉得有必要强调一下,以免误与他人.
而,这就是关于这一小段"额外"存在的理由.根据这个实际形式可以定义自己的浮点
数,用它来实现超大体积的浮点数、定点数的存储及计算,也或是超小体积.
继续就IEEE的标准做进一步说明与分析:
在前一小节的分析中没有关于"阶码的符号位"的描述.
然,偏移量为127 ; 127 = 1111111 (占用7bit).
偏移量 + 阶码的结果为正数会达到8bit宽,负数则只会小于8bit宽,因为阶码以补码
形式存储,那获得阶码必有一个计算过程即减去E_Disp,结果就是正数或负数,所以实际上
已经不需要阶码正负符号位或可以说成是:1表示正数;0表示负数.
到这里,我补充进来的目的应能让人很清楚了.这只是一种储存方式,必要的时候可
以不受限制的搬来灵活运用,自定义数据结构.
double型:
double 8byte 符号位1bit;阶码位11bit;尾数52bit
除了偏移量的不同即: 阶的偏移量 E_Disp = (2048/2 -1),其它的相同.