灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2100回复:0

浮点数计算精度控制

楼主#
更多 发布于:2012-09-10 18:54

大家一起和我来看一下下面的这段程序,它是关于浮点数计算精度控制。
//-----------------------------------------
double x=-29568;
double y=0.0001;
if(x+y>x)
MessageBox(0,"bigger","bigger",0);
else
{
MessageBox(0,"smaller","smaller",0);
exit(1);
}
//------------------------------------------
在我调试的那个工程中,x+y>x竟然为假,我切换到汇编窗口发现是下面的代码
//----------------------------
;if(x+y>x)
0043F218; fld; qword ptr [x]
0043F21E; fadd; qword ptr [y]
0043F224; fcomp;;;;;; qword ptr [x]
0043F22A; fnstsw; ax;;
0043F22C; test;;;;;;;;;; ah,41h
0043F22F; jne;;;;;;;;;;;; ......
//----------------------------
代码并没有错呀?问题出在哪儿呢?应该是fadd qword ptr [y]语句的执行精度的问题,因为执行这条语句后,st(0)的值竟然没变(即x+y=x).
进一步调试我发现,浮点数计算错误发生在一个函数(InitEngine)调用后,在此函数调用前就不会出这个问题。这个函数是一个引擎的初时化函数,无法知道他的具体实现,是什么原因造成了浮点计算错误呢?
编译选项设置不当?应该不会吧, 因为生成的汇编代码是正确的呀。在汇编代码正确的情况下,浮点计算精度太小,唯一的原因只能是fpu的状态错误了。我从网上搜到了intel的开发手册,找到介绍fpu的章节发现fpu的计算精度和它的控制寄存器中的两个bit位有关。重新调试程序并注意观察fpu的控制寄存器的变化,果然在调用函数前后fpu控制字由0x027f变为了0x007f,即fpu计算精度由双精度变为了单精度,明白了这点就不难明白上面的问题了,也就有了解决的办法。
解决办法:在InitEngine调用后执行下面两段代码之一:
方法一:
word fctrl=0x027f;
__asm
{
fldcw fctrl //fpu控制寄存器设为函数调用以前的值
}
方法二:
__asm
{
FINIT //重置fpu状态,注意此时fpu的精度将变为扩展精度而不是双精度
}



喜欢0 评分0
游客

返回顶部