我有一个软件项目,有时我会从小的、简单的浮点运算中得到奇怪的结果。我假设我错过了一些东西,并且想要一些关于如何调试以下问题的提示:
(使用的编译器是 MS VC 6.0,即 Microsoft C 编译器的 12 版)
第一个异常:
extern double Time, TimeStamp, TimeStep; // History terms, updated elsewhere
void timer_evaluation_function( ) {
if ( ( Time - TimeStamp ) >= TimeStep ) {
TimeStamp += TimeStep;
timer_controlled_code( );
}
{....}
由于某种原因,计时器评估失败并且计时代码从未执行。在调试器中,可以看到触发条件实际上是正确的,但 FPU 拒绝找到肯定的结果。以下代码段没有问题,尽管它执行相同的操作。通过插入可能允许失败的虚假评估来回避这个问题。
我猜 FPU 状态在某种程度上被早期执行的操作所污染,并且有一些编译器标志会有所帮助?
第二个异常:
double K, Kp = 1.0, Ti = 0.02;
void timed_code( ){
K = ( Kp * ( float ) 2000 ) / ( ( float ) 2000 - 2.0F * Ti * 1e6 )
{....}
结果是#IND,即使调试器将等式计算为大约 0.05。当使用 fld 指令将 2.0F 值加载到 FPU 时,#IND 值出现在 FPU 堆栈中。上一条指令使用 fild 指令将整数值 2000 作为双浮点数加载。一旦 FPU 堆栈包含 #IND 值,所有内容都将丢失,但调试器再次评估公式没有问题。稍后,这些操作会返回预期的结果。
此外,FPU 问题再次发生在函数调用之后。我应该在每个新函数之后插入清除 FPU 状态的浮点操作吗?是否存在可能以某种方式影响 FPU 的编译器标志?
在这一点上,我很感激所有的提示和技巧。
编辑:我设法通过在顶部函数中首先调用汇编函数 EMMS 来避免这个问题。这样,FPU 就可以清除在调用我的代码的环境中创建或未创建的任何 MMX 相关垃圾。FPU 的状态似乎不是理所当然的。
//坦率