加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

80x86汇编:关于浮点数的应用方法

(2019-04-10 11:02:57)
分类: 80x86
在 8086/8088 指令集中,并没有针对浮点数运算的指令。
升级到 386 以后,并用上了协处理器 387,这才支持浮点数运算。

这并不是说,8086/8088 就不能计算浮点数了。
只是 IEEE 所定义的浮点数格式,并不方便计算。

这也没什么。
编写几个子程序,就可以把浮点数,变换成适合 8086/8088 运算的数据。
比如,变换成一个字节的阶数、两个(或四个)字节的底数,都用补码形式。
然后,再计算起来,就没有什么障碍了。

====================================================
浮点数要点
====================================================

科学记数法

把一个数写成 a × 10^n 的形式,叫做科学记数法。
注意1:1 ≤ |a| < 10,即 a 的整数部分只有一位数。
注意2:10 的指数 n 为整数,可以是正数,也可以是负数。

一个十进制数按照科学记数法来写,如:
 ± 0.0135 = ± 1.35 * 10^-2
其中有三个部分:符号、a 的绝对值,以及10(进制)的指数。

当然,二进制数也可以这样写:
 ± 1101.1 = ± 1.1011 * 2^3
它也有三个部分:符号、a 的绝对值,以及二(进制)的指数。
-----------------------------------------
浮点数就是用科学记数法来表示的,即:
浮点数 = 符号尾数 * 2^阶码----句号意为小数点

;-----------------------------------------
IEEE 754 单精度浮点数格式如下:
|-Byte1---|-Byte2---|-Byte3---|-Byte4---|
|SJJJ JJJJ|JWWW WWWW|WWWW WWWW|WWWW WWWW|
其中:S=符号、J=阶码、W=尾数代码。
;-----------------------------------------
位数:用 32 位二进制代码,代表一个数字,则称为单精度浮点数。
   (用 64 位二进制代码,代表一个数字,则称为双精度浮点数。)
符号:占用 1 位代码,0、1 分别代表正号、负号。
数值a:包括 1 位整数 1,以及 23 位小数。
因为整数固定是 1,所以这个整数就不写(即隐藏)了。
在浮点数中只保存 a 的小数部分,故此称之为尾数。
尾数共占用 23 位二进制代码。
这 23 位代码,就决定了单精度浮点数的精度。
指数:还剩下的 8 位二进制代码,就用来保存指数。
8 位二进制补码形式,可以代表数字-128~127。
在存放到浮点数中之前,需要先把指数加上 127,这就称为阶码。
;-----------------------------------------

阶码的意义,见下表:

  阶 码   

 指 数 

0

  不代表指数。用来表示0,以及非规格数      

1

126

2

125

127

0

128

1

129

2

254

127

255

   不代表指数。用于表示无穷大、以及非数字   

 

可以看出,8 位阶码的范围是:0~255。

共有 256 种组合。
阶码为 0 和 255,另有他用,并不代表指数。
那么,代表指数的,就只有 254 种不同的组合了。
所以,阶码所代表指数的范围是:-126~+127。
;-----------------------------------------
由此可知,单精度浮点数可表示的绝对值范围:

(1.000……0 * 2^-126)~(1.111……1 * 2^127)

也就是: (1 * 2^-126)~(2 * 2^127)
对应十进制:1.18 * 10^-38 ~ 3.40 * 10^38
(计算器计算:2的-126次方、2的128次方,就能得出这两个数。)
;-----------------------------------------
注意,上面说的最小值,是规范的写法,即(隐藏的)整数位是1。
很多人,也就能理解到这个深度了。

为了表示更小的值,IEEE 754 特意规定了单精度浮点数的【非规格】格式:
即令阶码为零,尾数则可写为:.000……1~.111……1。

按照这种格式,(隐藏的)整数是 0 而不是 1。
这时的最小值,就是:
(0.000……1 * 2^-126)= 1 * 2^(-126-23) = 1.40 * 10^-45

;如果阶码和 23 位尾数都是 0,这可就真是 0 了,这才是真正的最小值。
;-----------------------------------------
求浮点数范围的 java 代码如下:
float maxf = Float.MAX_VALUE;//最大值
float minf = Float.MIN_VALUE;//最小值
System.out.println("单精度浮点数范围:" + minf + "~" + maxf + "。");

double maxd = Double.MAX_VALUE;//最大值
double mind = Double.MIN_VALUE;//最小值
System.out.println("双精度浮点数范围:" + mind + "~" + maxd + "。");

运行后,结果输出如下:

单精度浮点数范围:1.4E-45 ~ 3.4028235E38。
双精度浮点数范围:4.9E-324 ~ 1.7976931348623157E308。
;====================================================
很多书籍和网文,介绍浮点数的最小值时,都不全面,误导了读者。
包括“百度百科”,也把单精度浮点数的最小值写错了,呵呵
;====================================================
另外,刚才说到了:23 位二进制的尾数,就决定了单精度浮点数的精度。
实际上,还应该算上 1 位整数。
那么,就是 24 位二进制数,决定了精度。

但是,用二进制表示精度,有点难。一般人都不会理解,应该转换成十进制。
0~2^ 24-1,这是二进制的范围,换算成十进制就是:0~16,777,215。
这就是说,24位二进制数,近似相当于 8 位十进制数。

但是,真的能达到 8 位十进制数?
首位,是不会大于 1 的。
首位是 0 时,后面 7 位数还可以随便变化,即:00,000,000~09,999,999。
但是当首位等于 1 时,后 7 位变化有限了,即:10,000,000~16,777,215。
首位,也不可能是其它数值。

因此,24 位二进制数,可以完满的相当于 7 位十进制数。
相当于 8 位十进制数?
这就很勉强了,因为首位不能完全的表示 1~9。
最多,只是有个 1 而已,而且此时,低 7 位只能是 0~6,777,215。
所以,相当于 8 位十进制数,只有 8% 的可能性。
;====================================================
说了这么多,还是要回到原来的话题,怎么应用浮点数。
由于有阶码,浮点数就可表示极大、极小的数值,但是,绝大部分是用不上的。
由于尾数的位数有限,浮点数的精度,就有些尴尬了。

那么,最简单的方法是,采用定点数。
比如,用 8 字节表示一个数,中间是小数点。
4 字节整数、4 字节小数,这样的范围、精度,都可以满足一般的需求。

如果还觉得不够,就再加大字节数。
现在计算机存储器的容量,已经不像几十年前那样局促了,可以撒欢的用。
把浮点数中的信息分离开,再换算成定点数,这还难吗?
都用不上 10 条指令。
以后的计算,就是多字节的加减乘除了,做而论道以前都是介绍过的。

说明:做而论道,是本博主在百度开博所用的网名。
在新浪这里,只能另外起名为:黄渤之间,以纪念行走多年的地方。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有