FPU 特殊作用寄存器中有一个控制寄存器,该寄存器的作用是控制浮点数计算结果的四舍五入以及对相关异常的静默处理
Control word寄存器含有16位,可以将其内容保存在一个WORD 大小的内存变量中。我们来看看它的内容是什么样的
第几位 描述
0 无效操作异常掩码
1 非正交化异常掩码
2 除以0异常掩码
3 Overflow异常掩码
4 UnderFlow异常掩码
5 精度异常掩码
8-9 精度控制
10-11 四舍五入控制
12 无穷大控制
对于如下C++代码:
int x = 1;
double y = 2.5;
int z = (int)(x+y);
使用Visual C++编译器编译时,当结果保存到z之前,会调用一个叫做ftol的函数。假如,我们使用fist指令,就可以避免函数调用:
fild x ; 将x加载到ST(0)寄存器中
fadd y ; x + y 结果保存在ST(0)中
fist z ; 将结果保存到z中
然而,这样计算的结果却是4,因为默认的四舍五入规则是四舍五入到最近的偶数,总共有四种四舍五入规则,见下面:
FPU控制字在RC位中(10-11)含有两位表示四舍五入的方法:
00: 四舍五入到最近的偶数(默认)
01: 四舍五入至无穷小
10: 四舍五入到无穷大
11: 四舍五入至0
我们知道,只要把FPU的RC字段改成11即可,故可以使用下面的汇编代码:
fstcw ctrlWord ; 保存控制字
or ctrlWord,0000110000000000b ; 使用四舍五入至0方法
fldcw ctrlWord
fild x
fadd y
fist z
fstcw ctrlWord
and 1111001111111111b
fldcw ctrlWord
这样,计算的结果就与C++相同了。
FPU之于异常
每种异常类型都有相应的标记位和掩码位。当FPU检测到异常时,处理器设置相应的标记位。对于每个被CPU标记的异常来说,有两种结果:
1. 假如相应的掩码位为1,那么处理器自动处理该异常,然后程序继续执行,这是默认情况
2. 假如相应的掩码位为0,那么处理器将调用异常处理器。
鉴于上面的阐述,我们可以改变控制字寄存器的第2位,达到是否处理除0异常。