浮点运算简介
对于习惯于C的灵活多变的数据类型和方便的计算那些人而言,了解底层的浮点运算似乎没有什么意义,现在Visual盛行的时代还有多少人关心那些所谓的底层呢?
对了AfOs来说,浮点运算是编程中很重要的一部分,因为我们可能会面临一些稍微复杂的运算,如果你和我一样是Die-hard的asm拥护者,不想轻易用C来解决问题,你肯定能想像在asm下用整数运算求sin(2.3)的痛苦,实际上,微机早就为我们准备了解决之道:那就是浮点运算.但现在关于浮点运算的资料较少,相信很多人和我一样还不掌握这种强有力的技术,那好,我们一起来学习学习.
(一)浮点数
(This Part mainly Froe Bill's Article)
在这之前,先来看几个术语:
FPU->Floating Point Unit,浮点运算部件
BCD->Binary Coded Decimal 压缩的二十进制数,是用4个位来表示数字0~9,一个byte表示两个十进制数,比如01111001表示89
科学计数法:这是科学的~~~~具体含义查查初中还是小学的数学课本 D:)
浮点运算使用三种不同的数据:
1)整数(Integer),又分为字,短整数(Short Integer)和长整数(Long Integer)
2)实数(Real)分单精度(Single Real)和双精度(Double Real)
3)压缩的二十进制数(BCD)
下面是其位数(bits)和能表示的大致范围和
Type Length Range
-----------------------------------------------
Word Integer 16 bit -32768 to 32768
Short Integer 32 bit -2.14e9 to 2.14e9
Long Integer 64 bit -9.22e18 to 9.22e18
Single Real 32 bit 1.18e-38 to 3.40e38
Double Real 64 bit 2.23e-308 to 1.79e308
extended Real 80 bit 3.37e-1932 to 1.18e4932
Packed BCD 80 bit -1e18 to 1e18
双精度数和扩展精度数表示范围对一般应用来说已经足够大了!
1)整数,以补码形式存储,正数的补码是其本身,负数补码是其绝对值的各位变反后加1,下面是实际存储的例子:
0024 var1 dw 24
FFFE var2 dw -2
000004D2 var3 dd 1234
FFFFFF85 var4 dd -123
0000000000002694var5 dq 9876
FFFFFFFFFFFFFEBFvar6 dq -321
2)BCD数
在FPU中用80位表示正好是浮点堆寄存器的宽度,在其格式如下存储:
Bit
79___72_71________________________________________0
符号 ---18个二十进制数--------
看下面的例子:
00000000000000012345 var1 dt 12345
80000000000000000100 var2 dt -100
3)浮点数,这个复杂点,有三种格式
单精度:_31_30________23_22___________0
符号 指数 有效数
双精度:_63_62__________52_51__________________0
符号 指数 有效数
扩展精度数:
_79_78____________64_63___________________0
符号 指数 有效数
例子:
C377999A var1 dd -247.6
40000000 var2 dd 2.0
486F4200 var3 real4 2.45e+5
4059100000000000 var4 dq 100.25
3F543BF727136A40 var5 real8 0.00123
C377999A var1 dd -247.6
40000000 var2 dd 2.0
486F4200 var3 real4 2.45e+5
4059100000000000 var4 dq 100.25
3F543BF727136A40 var5 real8 0.001235
400487F34D6A161E4F76 var6 real10 33.9876
DD和real4都可以在asm中来定义单精度浮点数,4 bytes
DQ和real8都可以在asm中来定义双精度浮点数,8 bytes
DT和real10都可以在asm中来定义扩展精度浮点数,10 bytes
(二)浮点部件
FPU从功能上分为两个部分:控制单元和运算单元,控制单元主要面向CPU,而算数单元负责具体算数运算.
FPU即浮点部件包括8个通用寄存器,5个错误指针寄存器和三个控制寄存器.
1)8个通用寄存器每个80 bit,形成一个寄存器堆栈,所有的计算结果都保存在寄存器堆栈中,其中数据全部是80位的扩展精度格式,即使是BCD,整数,单精度和双精度等在装入寄存器的时候都要被FPU自动转化为80位的扩展精度格式,注意栈顶通常表示为ST(0),然后是ST(1)...ST(i),ST(i)是相对于栈顶而言的.
和堆栈很相似,只不过宽度为80bit,映像如下:
_______________________
| ST(0) |
|_______________________|
| ST(1) |
|_______________________|
| ...... |
| ...... |
| ST(i) |
|_______________________|
2)控制寄存器,FPU有三个控制寄存器:状态寄存器,控制寄存器和标记寄存器
状态寄存器->SW
_M_____D________10___9____8___7_________5_________________________0__
| B | C3| TOP| C2 | C1 | C0 | ES | | PE | UE | OE | ZE | DE | IE |
|____|____|____|____|____|____|____|____|____|____|____|____|____|____|
B: 浮点部件正忙
C0-C3 指示浮点运算的结果,不同指令有不同含义
TOP 指示栈顶,通常是0
ES 以下任何位置位 (pe, ue, oe, ze, de, or ie) 则置位
PE 精度故障
UE 数字太小无法表示溢出
OE 现有精度无法表示,数字太大溢出
ZE 除0错
DE 指示至少有一个操作数未规格化
IE 无效错误,指示堆栈上溢或下溢,无效操作数等
控制寄存器:
_15____________10___9____8___7_________5______________________0__
| |IC | RC | PC | | PM | UM | OM | ZM | DM | IM |
|____|____|____|___|__|_|__|__|____|____|____|____|____|____|____|
IC 无穷大控制,对486,已经无效
RC 舍入控制
00 = 朝最接近或者偶数舍入
01 = 朝负无穷大方向舍入
10 = 朝正无穷大方向舍入
11 = 超0方向截断
PC 精度控制
00 = 单精度
01 = 保留
10 = 双精度
11 = 扩展精度
PM~IM 屏蔽状态寄存器低5位指示的错误.为1则屏蔽.
标记寄存器:
每2 bit表示一个对应堆栈寄存器的状态,具体含义如下:
15________________________________________3_____0
|Tag7 |...................................|tag1|
|_____|___________________________________|____|
含义:
00 = 有效
01 = 零
10 = 无效或无穷大
11 = 为空
|