Strange results with / fp: fast

We have code that looks like this:

inline int calc_something(double x) { if (x > 0.0) { // do something return 1; } else { // do something else return 0; } } 

Unfortunately, when using the /fp:fast flag, we get calc_something(0)==1 , so we obviously take the wrong code path. This happens only when we use the method at several points in our code with different parameters, so I think that there is some kind of fish optimization from the compiler (Microsoft Visual Studio 2008, SP1).

In addition, the above problem disappears when we change the interface to

 inline int calc_something(const double& x) { 

But I have no idea why this captures strange behavior. Can anyone explain this behavior? If I do not understand what is going on, we will have to remove the /fp:fast switch, but this will make our application rather slow.

+4
source share
5 answers

I am not familiar enough with FPU to comment with any certainty, but I assume that the compiler allows the existing value, which in his opinion should be equal to x , to sit in this comparison. Perhaps you go y = x + 20.; y = y - 20; y = x + 20.; y = y - 20; y already on the FP stack, so instead of loading x compiler simply compares with y . But due to rounding errors, y not quite 0.0 , as expected, and you get the odd results you see.

For a better explanation: Why cos (x)! = Cos (y), although x == y? from C ++ FAQ lite. This is part of what I'm trying to understand, I just could not remember exactly where I read it so far.

Changing the const reference fixes this because the compiler is concerned about the alias. It forces the load from x , because it cannot be assumed that its value did not change at some point after y , and since x is actually exactly 0.0 [which appears in every floating-point format, I am "familiar") rounding errors disappear.

I'm sure MS provides a pragma that allows you to set FP flags based on each function. Or you can transfer this procedure to a separate file and provide these flags for the file. In any case, this may prevent your program from suffering completely in order to maintain this ordinary joy.

+6
source

As I said in another question, compilers suck when generating floating point code. Dennis's article explains the problems. Here is another: MSDN article .

If code performance is important, you can easily run the compiler 1 by writing your own assembler code. If your algorithm is vectorized, you can also use SIMD (with a slight loss of accuracy).

  • Assuming you understand how FPU works.
+3
source

what are the results of calc_something(0L) , or calc_something(0.0f) ? It may be related to size types before casting. An integer is 4 bytes, double is 8.

Have you tried looking at the compiled code to see how the above conversion works?

Googling for 'fp fast', I found this post [social.msdn.microsoft.com]

+2
source

inline int calc_something(double x) will (probably) use an 80-bit register. inline int calc_something(const double& x) will store the double in memory, where it takes 64 bits. This at least explains the difference between the two.

However, I think your test is very problematic to start with. The results of calc_something extremely sensitive to rounding its input. Your FP algorithms must be robust for rounding. calc_something(1.0-(1.0/3.0)*3) should be the same as calc_something(0.0) .

+2
source

I believe that the behavior is correct.

You never compare floating point numbers less than hold type precision.

That which comes from zero may be equal to greater or less than another zero.

See http://floating-point-gui.de/

+1
source

Source: https://habr.com/ru/post/1312835/


All Articles