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 为整数,可以是正数,也可以是负数。
一个十进制数按照科学记数法来写,如:
其中有三个部分:符号、a
的绝对值,以及10(进制)的指数。
当然,二进制数也可以这样写:
它也有三个部分:符号、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 |
|
|
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
条指令。
以后的计算,就是多字节的加减乘除了,做而论道以前都是介绍过的。
说明:做而论道,是本博主在百度开博所用的网名。
在新浪这里,只能另外起名为:黄渤之间,以纪念行走多年的地方。

加载中…