直到 20 世纪 80 年代(即在没有制定 IEEE 754 标准之前),业界还没有一个统一的浮点数标准。相反,很多计算机制造商根据自己的需要来设计自己的浮点数表示规则,以及浮点数的执行运算细节。另外,他们常常并不太关注运算的精确性,而把实现的速度和简易性看得比数字的精确性更重要,而这就给代码的可移植性造成了重大的障碍。
直到 1976 年,Intel 公司打算为其 8086 微处理器引进一种浮点数协处理器时,意识到作为芯片设计者的电子工程师和固体物理学家也许并不能通过数值分析来选择最合理的浮点数二进制格式。于是,他们邀请加州大学伯克利分校的 William Kahan 教授(当时最优秀的数值分析家)来为 8087 浮点处理器(FPU)设计浮点数格式。而这时,William Kahan 教授又找来两个专家协助他,于是就有了 KCS 组合(Kahn、Coonan和Stone),并共同完成了 Intel 公司的浮点数格式设计。
由于 Intel 公司的 KCS 浮点数格式完成得如此出色,以致 IEEE(Institute of Electrical and Electronics Engineers,电子电气工程师协会)决定采用一个非常接近 KCS 的方案作为 IEEE 的标准浮点格式。于是,IEEE 于 1985 年制订了二进制浮点运算标准 IEEE 754(IEEE Standard for Binary Floating-Point Arithmetic,ANSI/IEEE Std 754-1985),该标准限定指数的底为 2,并于同年被美国引用为 ANSI 标准。目前,几乎所有的计算机都支持 IEEE 754 标准,它大大地改善了科学应用程序的可移植性。
考虑到 IBM System/370 的影响,IEEE 于 1987 年推出了与底数无关的二进制浮点运算标准 IEEE 854,并于同年被美国引用为 ANSI 标准。1989 年,国际标准组织 IEC 批准 IEEE 754/854 为国际标准 IEC 559:1989。后来经修订后,标准号改为 IEC 60559。现在,几乎所有的浮点处理器完全或基本支持 IEC 60559。同时,C99 的浮点运算也支持 IEC 60559。
IEEE 浮点数标准是从逻辑上用三元组{S,E,M}来表示一个数 V 的,即 V=(-1)S×M×2E,如图1 所示。
图 1
其中:
符号位 s(Sign)决定数是正数(s=0)还是负数(s=1),而对于数值 0 的符号位解释则作为特殊情况处理。
有效数字位 M(Significand)是二进制小数,它的取值范围为 1~2-ε,或者为 0~1-ε。它也被称为尾数位(Mantissa)、系数位(Coefficient),甚至还被称作“小数”。
指数位 E(Exponent)是 2 的幂(可能是负数),它的作用是对浮点数加权。
浮点数格式是一种数据结构,它规定了构成浮点数的各个字段、这些字段的布局及算术解释。IEEE 754 浮点数的数据位被划分为三个段,从而对以上这些值进行编码。其中,一个单独的符号位 s 直接编码符号 s;k 位的指数段 exp=ek-1…e1e0,编码指数 E;n 位的小数段 frac=fn-1…f1f0,编码有效数字 M,但是被编码的值也依赖于指数域的值是否等于 0。
根据 exp 的值,被编码的值可以分为如下几种不同的情况。
1) 格式化值
当指数段 exp 的位模式既不全为 0(即数值 0),也不全为 1(即单精度数值为 255,以单精度数为例, 8 位的指数为可以表达 0~255 的 255 个指数值;双精度数值为 2047)的时候,就属于这类情况。如图 2 所示。
图 2
我们知道,指数可以为正数,也可以为负数。为了处理负指数的情况,实际的指数值按要求需要加上一个偏置(Bias)值作为保存在指数段中的值。因此,这种情况下的指数段被解释为以偏置形式表示的有符号整数。即指数的值为:E=e-Bias
其中,e 是无符号数,其位表示为 ek-1…e1e0,而 Bias 是一个等于 2k-1-1(单精度是 127,双精度是 1023)的偏置值。由此产生指数的取值范围是:单精度为 -126~+127,双精度为 -1022~+1023。
对小数段 frac,可解释为描述小数值 f,其中 0≤f<1,其二进制表示为 0.fn-1…f1f0,也就是二进制小数点在最高有效位的左边。有效数字定义为 M=1+f。有时候,这种方式也叫作隐含的以 1 开头的表示法,因为我们可以把 M 看成一个二进制表达式为 1.fn-1fn-2…f0 的数字。既然我们总是能够调整指数 E,使得有效数字 M 的范围为 1≤M<2(假设没有溢出),那么这种表示方法是一种轻松获得一个额外精度位的技巧。同时,由于第一位总是等于 1,因此我们就不需要显式地表示它。拿单精度数为例,按照上面所介绍的知识,实际上可以用 23 位长的有效数字来表达 24 位的有效数字。比如,对单精度数而言,二进制的 1001.101(即十进制的 9.625)可以表达为 1.001101×23,所以实际保存在有效数字位中的值为:
00110100000000000000000
即去掉小数点左侧的 1,并用 0 在右侧补齐。
根据上面所阐述的规则,下面以实数 -9.625 为例,来看看如何将其表达为单精度的浮点数格式。具体转换步骤如下:
1、首先,需要将 -9.625 用二进制浮点数表达出来,然后变换为相应的浮点数格式。即 -9.625 的二进制为 1001.101,用规范的浮点数表达应为 1.001101×23。
2、其次,因为 -9.625 是负数,所以符号段为 1。而这里的指数为 3,所以指数段为 3+127=130,即二进制的 10000010。有效数字省略掉小数点左侧的 1 之后为 001101,然后在右侧用零补齐。因此所得的最终结果为:
3、最后,我们还可以将浮点数形式表示为十六进制的数据,如下所示:
即最终的十六进制结果为 0xC11A0000。
先将实数由十进制转换为二进制数
例 5865.236
整数部分:5865 =BIN 1 0110 1110 1001
小数部分:.236 =BIN 00111100011010100111111
5865.236=1.0110 1110 1001 ,001111000110101
利用上述工程,使用科学计数法记录
5865.236=1,0110 1110 1001111000110101x212
12+127=139 二进制表示为10001011,
故指数部分表示为10001011
小数部分为科学计数法的后23位
即0110 1110 1001111000110101
5865.23=0 10001011 01101110100100111100011
符号位 指数位 小数位