4

我有一个软件项目,有时我会从小的、简单的浮点运算中得到奇怪的结果。我假设我错过了一些东西,并且想要一些关于如何调试以下问题的提示:

(使用的编译器是 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 的状态似乎不是理所当然的。

//坦率

4

6 回答 6

2

不知道问题可能是什么,但在 x86 上,FINIT 指令清除了 FPU。要测试您的理论,您可以将其插入代码中的某处:

__asm {
    finit
}
于 2009-01-26T17:35:47.277 回答
1

这并不是您问题的真正答案,但您可能想查看 Raymond Chen 关于奇怪 FPU 行为的两篇文章。阅读您的问题并重新阅读文章后,我没有立即看到链接 - 但如果您粘贴的代码不完整,或者文章让您了解导致问题的一些周围行为.. . 特别是,如果您在附近的任何地方加载 DLL。

未初始化的浮点变量可能是致命的

当我禁用无效浮点操作数异常时,它是如何引发的?

于 2009-01-26T22:21:29.710 回答
1

如果您在支持 MMX 的系统上使用 Windows QueryPerformanceCounter 和 QueryPerformanceFrequency 函数,请尝试在查询频率/计数器之后和计算之前插入 femms 指令。

__asm femms

在他们使用 MMX 进行 64 位计算并且不清除浮点标志/状态之前,我遇到了这些函数的问题。

如果浮点运算之间存在任何 64 位运算,也可能发生这种情况。

于 2009-01-27T00:36:36.707 回答
0

虽然我没有为您提供确切的解决方案,但我建议您先阅读这篇描述可以使用的不同优化的文章。

于 2009-01-26T17:31:38.890 回答
0

回复:时间戳——

您从什么获得时间戳的来源?听起来有些可疑。尝试将它们记录到文件中。

于 2009-01-26T18:17:59.297 回答
0

如果错误值由应该加载 2.0 的 fld 加载,我会检查加载该值的内存 - 这可能只是编译器/链接器问题。

于 2009-01-27T00:02:31.440 回答