Strange results from simple floating point operations - bad internal state of FPU?

I have a software project in which I sometimes get strange results from small simple floating point operations. I assume that there is something that I missed and would like to get some tips on how to debug the following issues:

(MS VC 6.0 compiler is used, i.e. version 12 of the Microsoft C compiler)

First anomaly:

extern double Time, TimeStamp, TimeStep; // History terms, updated elsewhere void timer_evaluation_function( ) { if ( ( Time - TimeStamp ) >= TimeStep ) { TimeStamp += TimeStep; timer_controlled_code( ); } {....} 

For some reason, timer evaluation failed, and the programmed code never ran. There was no problem in the debugger to see that the trigger condition was really true, but the FPU refused to find a positive result. The next segment of code had no problems, although it performed the same operations. The problem was circumvented by inserting a dummy score that could be resolved.

I assume that the state of the FPU is somehow corrupted by previous operations performed and that there are some compiler flags that will help?

Second anomaly:

 double K, Kp = 1.0, Ti = 0.02; void timed_code( ){ K = ( Kp * ( float ) 2000 ) / ( ( float ) 2000 - 2.0F * Ti * 1e6 ) {....} 

Result: #IND, although the debugger evaluates the equation to about 0.05. The #IND value appears on the FPU stack when 2.0F is loaded into the FPU using the fld command. The previous statement loads the integer value 2000 as a double float using the fild command. Once the FPU stack has the #IND value, everything will be lost, but again the debugger has no problem evaluating the formula. Later, these operations return the expected results.

In addition, again FPU problems occur immediately after a function call. Should I insert floating point operations that clear the state of the FPU after each new function? Is there a compiler flag that could somehow affect the FPU?

I am grateful to all and all the tips and tricks at this stage.

EDIT: I managed to avoid the problem by calling the EMMS build function first thing in the top function. Thus, the FPU is cleared of any garbage associated with the MMX, which may or may not be created in the environment from which my code is called. It seems that the state of the FPU is not something taken for granted.

//Franc

+4
source share
6 answers

If you use the QueryPerformanceCounter and QueryPerformanceFrequency windows on a system that supports MMX, try inserting the femms statement after asking for the frequency / counter and before calculating.

 __asm femms 

I ran into a problem with this function until where they performed 64-bit computation using MMX and did not clear the flags / floating point status.

This situation can also occur if 64-bit arithmetic exists between floating point operations.

+1
source

I don't know what the problem is, but on x86, FINIT instructions clear the FPU. To test your theory, you can paste this somewhere in your code:

 __asm { finit } 
+2
source

This is not an answer to your question, but you can look at two articles by Raymond Chen regarding strange FPU behavior. After reading your question and re-reading the articles, I do not immediately see the link, but if the code you inserted is not complete, or if the articles give you an idea of ​​some kind of environmental behavior that caused the problem. in particular, if you download the DLL somewhere nearby.

Uninitialized floating point variables can be fatal

How did an invalid floating-point operand exception occur when I turned it off?

+1
source

Until I provide you with the exact solution, I suggest you start by reading this article which describes the various optimizations that you can use.

0
source

re: timestamps -

How do you get your timestamp source? Something sounds suspicious. Try writing them to a file.

0
source

If a bad value is loaded by fld, which should load 2.0, I would check the memory into which this value is loaded, it could just be a compiler / linker problem.

0
source

All Articles