我有一个软件项目,我有时会从小而简单的浮点运算中得到奇怪的结果。我假设有一些我错过的东西,并想了解如何调试以下问题的一些提示:
(使用的编译器是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( );
}
{....}
由于某种原因,计时器评估失败,定时代码从未执行。在调试器中,没有问题看到trig条件实际上是真的但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时,#INT值出现在FPU堆栈中。上一条指令使用fild指令将整数值2000加载为double float。一旦FPU堆栈包含#IND值,一切都会丢失,但调试器再一次评估公式没有问题。稍后,这些操作将返回预期的结果。
此外,在函数调用之后,FPU问题再次出现。我应该在每个新函数后插入清除FPU状态的浮点运算吗?是否存在可能以某种方式影响FPU的编译器标志?
我很感激此时的所有提示和技巧。
编辑:我已经设法通过在top函数中调用汇编函数EMMS来避免这个问题。这样,FPU就可以清除任何MMX相关的垃圾,这些垃圾可能是在我的代码被调用的环境中创建的,也可能没有。似乎FPU的状态不是理所当然的。//弗兰克
答案 0 :(得分:2)
不知道问题是什么,但在x86上,FINIT指令会清除FPU。要测试您的理论,您可以在代码中的某处插入:
__asm {
finit
}
答案 1 :(得分:1)
这不是你问题的答案,但你可能想看看Raymond Chen关于奇怪的FPU行为的两篇文章。阅读完您的问题并重新阅读文章后,我不会立即看到一个链接 - 但如果您粘贴的代码不完整,或者文章让您了解导致问题的某些周围行为。特别是,如果你在附近的任何地方加载DLL。
Uninitialized floating point variables can be deadly
How did the invalid floating point operand exception get raised when I disabled it?
答案 2 :(得分:1)
如果您在支持MMX的系统上使用Windows QueryPerformanceCounter和QueryPerformanceFrequency函数,请在查询频率/计数器之后和计算之前插入femms指令。
__asm femms
在使用MMX进行64位计算而不清除浮点标志/状态之前,我遇到过这些函数的问题。
如果浮点运算之间存在任何64位运算,也会发生这种情况。
答案 3 :(得分:0)
虽然我没有向您提供确切的解决方案,但我建议您先阅读此article,其中介绍了可以使用的不同优化方法。
答案 4 :(得分:0)
re:timestamps -
您从什么时候获得时间戳来源?有些东西听起来很可疑。尝试将它们记录到文件中。
答案 5 :(得分:0)
如果错误值由应加载2.0的fld加载,我会检查加载此值的内存 - 它可能只是编译器/链接器问题。