浮点数计算精度控制
3168 点击·0 回帖
![]() | ![]() | |
![]() | 大家一起和我来看一下下面的这段程序,它是关于浮点数计算精度控制。 //----------------------------------------- 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的精度将变为扩展精度而不是双精度 } | |
![]() | ![]() |