标题:浮点类型深谈
1.编写本文目的
浮点运算已属常用,但仍有深究必要,以消除其中可能的错误使用。
2.预期读者
3.编者语
㈠ 在其他任何公共论坛上转载本文,请标明出处和作者,而无需授权和确认。
4.正文
㈠ float格式简谈
Inter 80386/80387 及以上型号CPU有三种浮点类型,即短实数、长实数和80位临时实数,分别占用4字节、8字节和10字节,对应着C/C++中的float、double和long double[注1],我以 Real4、Real8和Real0表示之。
每种浮点格式皆应符合IEEE标准,称为规格化数,不符合IEEE标准的浮点格式称为非格式化数(NAN),我以最简单的float格式举例。
Float格式数据长32 bits,最高位为符号位:0为正,1为负;紧接着的8位为阶码:为了便于比较大小,其固定偏移7FH长,即0实际表示-7FH,7FH实际表示0,0FFH实际表示80H;余下的低23位为尾数(有效数字),为了使有效数字达到最大精度,这23个有效数字隐含着固定位1[注2],比如尾数10000000000000000000001其实就是1.10000000000000000000001,1被省略,而小数点固定在首位。
根据以上规则可以知道float所能表示的绝对值大小范围是
0 000,0000,0 000,0000,0000,0000,0000,0000 B 至
0 111,1111,1 111,1111,1111,1111,1111,1111 B
即±1.00000000000000000000000B×2(0x00-0x7F) 到±1.11111111111111111111111B×2(0xFF-0x7F)
然而事实上并不是这样,因为从这个范围可以看出它并不能表示0.0,而0.0为常用数字,所以特别规定±1.00000000000000000000000B×200为零,规定指数为0xFF的数字为非法数字,因此float实际的绝对值范围(除去0以外)是
0 000,0000,0 000,0000,0000,0000,0000,0001 B 至
0 111,1111,0 111,1111,1111,1111,1111,1111 B
即 0 并上 ±1.00000000000000000000001B×2(0x00-0x7F) 到±1.11111111111111111111111B×2(0xFE-0x7F)
可能的格式状态:
+不支持
+非有效数
-不支持
-非有效数
+规格化
+∞
-规格化
-∞
+0
+空
-0
-空
+不能规格化
-不能规格化
可能的异常:
无效操作
上溢
下溢
除零
不可规格化操作数
精度不足
㈡ 注意事项
a. 可以看出0可以用+0表示,也可以用-0表示,为此,CPU在比较零值时作了特殊处理,结果是±0虽然在存储器上格式不同,但比较值相同,然而如果是用字节来比较float类型大小时却需要注意这一点。
b. 运算上溢的值不是实际值,而是特值 0 111,1111,0 000,0000,0000,0000,0000,0000 B,例如 1.0×2127 + 1.5×2127 不等于 1.5×2128,虽然它有能力表示1.5×2128。
c.
㈢ 在C++中的部分解决方案及遗留问题
5.参考资料
《Inter 80X86/80387 汇编指南》
6.附录
[注1]:M$认为double精度已足够,故在MVC++5.0及以后取消80位了临时实数,令long double等同于double,但在本文中的long double还是指80位临时实数。
[注2]:各种浮点类型格式类似,double指数偏移基数3FFH,long double指数偏移基数3FFFH,但long double特殊在无有效数字隐含位。
real04:符号位1,阶码08(固定偏移 7F),尾数23,固定隐含位有;
real08:符号位1,阶码11(固定偏移 3FF),尾数52,固定隐含位有;
real10:符号位1,阶码15(固定偏移3FFF),尾数64,固定隐含位无;