VC++ floating point code generation & /Op setting 
Author Message
 VC++ floating point code generation & /Op setting

Hi Experts,

I noticed the following common problem when dealing with floating point
operations in VC++. Consider the following code.

float f() { ... }
float g() { ... }
...
if (f() == g()) ... else ...

Now assume that the f and g functions return the same! value. However, when
executing the if statement, the condition fails.

Examining of the assembly shows that the result of the call to the f
function is copied from the floating point stack in the FPU into a dword in
memory, then g function is called, and finally, result of the g function
still sitting on the FPU's floating point stack is compared to the result
stored in dword in memory. When the 32bit representation stored in dword
differs from the 80bit representation on the stack, the comparison fails
even though the "float" values are the same... (same applied to 64bit
doubles)

This is a serious and I expect common issue. I hate ugly code and don't want
to resort to tests like if (f() - g() <= ALMOST_NOTHING) ... neither do I
want to create temporary variables to hold results of the two function calls
just to strip down the extra bits (this could also collide with the
optimizer). So, I was looking for a project setting to control this aspect
of the code generation in VC++. Really, all I need is to guarantee the same
precision for the two return values (I don't care whether both are copied
into dwords or kept on the FPU stack which is faster and shorter, as long as
they are the same and the comparison works).

I found the /Op setting to "improve floating-point consistency". I though it
was just what I was looking for but it turned out this setting does not
affect the above code.

Are you guys aware of any other compiler setting? Or at least an elegant way
to deal with this in VC++? (It seems that VB by default converts floating
point
results to either float or double and that it actually has a switch to
disable this to produce tighter and faster but possibly failing! code. I am
not a VB expert but would be surprised if VB had such an option and VC++ did
not.)

Thanks for any advise,

Peter



Tue, 12 Nov 2002 03:00:00 GMT  
 VC++ floating point code generation & /Op setting
Peter,

Could you please show under which circumstances comparision
fails? AFAIK fcomp dword ptr [xxx] loads real into FPU and
makes compirision there. Following should produce EQ flag set:
    fld dword ptr [x]
    fcomp dword ptr [x]

--
Best regards,
Igor.
[if replying by email please reply to itereshATuswestDOTnet]


Quote:
> Hi Experts,

> I noticed the following common problem when dealing with floating point
> operations in VC++. Consider the following code.

> float f() { ... }
> float g() { ... }
> ...
> if (f() == g()) ... else ...

> Now assume that the f and g functions return the same! value. However,
when
> executing the if statement, the condition fails.

> Examining of the assembly shows that the result of the call to the f
> function is copied from the floating point stack in the FPU into a dword
in
> memory, then g function is called, and finally, result of the g function
> still sitting on the FPU's floating point stack is compared to the result
> stored in dword in memory. When the 32bit representation stored in dword
> differs from the 80bit representation on the stack, the comparison fails
> even though the "float" values are the same... (same applied to 64bit
> doubles)

> This is a serious and I expect common issue. I hate ugly code and don't
want
> to resort to tests like if (f() - g() <= ALMOST_NOTHING) ... neither do I
> want to create temporary variables to hold results of the two function
calls
> just to strip down the extra bits (this could also collide with the
> optimizer). So, I was looking for a project setting to control this aspect
> of the code generation in VC++. Really, all I need is to guarantee the
same
> precision for the two return values (I don't care whether both are copied
> into dwords or kept on the FPU stack which is faster and shorter, as long
as
> they are the same and the comparison works).

> I found the /Op setting to "improve floating-point consistency". I though
it
> was just what I was looking for but it turned out this setting does not
> affect the above code.

> Are you guys aware of any other compiler setting? Or at least an elegant
way
> to deal with this in VC++? (It seems that VB by default converts floating
> point
> results to either float or double and that it actually has a switch to
> disable this to produce tighter and faster but possibly failing! code. I
am
> not a VB expert but would be surprised if VB had such an option and VC++
did
> not.)

> Thanks for any advise,

> Peter



Tue, 12 Nov 2002 03:00:00 GMT  
 VC++ floating point code generation & /Op setting
On Fri, 26 May 2000 13:34:33 -0700, "Peter Veprek"

Quote:

>float f() { ... }
>float g() { ... }
>...
>if (f() == g()) ... else ...

Sooner or later you will shoot yourself in the foot using such
constructions.

If f() or g() does anything more complicated than assigning floating
point constants to the return value, sooner or later the results are
going to be slightly different even if mathematically the equations
are the same.

Quote:
>This is a serious and I expect common issue.

The behaviour of floating point number is a very common issue and this
is usually one of the first things that dealt with in lectures of
numeric analysis.

Quote:
>I hate ugly code and don't want
>to resort to tests like if (f() - g() <= ALMOST_NOTHING) ... neither do I

Make that (fabs(f()-g()) <= ALMOST_NOTHING) ...

This has been the standard practice for decades, long before Windows
or x86/x87 processors. If you think this is ugly, why don't you just
define a macro containing that expression and in your code use
expressions like

if (isEQ(f(),g()) ...

If the magnitude of the floating point values can vary greatly, why
not just write a (possibly inline) function like

inline int IsEQ(float a, float b)
{
    return abs(a-b) <= abs(ALMOST_NOTHING*a) ;

Quote:
}

If this is still too ugly and you are using C++, why not overload the
"==" and "!=" operators with a code segment similar to that above.

Paul



Wed, 13 Nov 2002 03:00:00 GMT  
 VC++ floating point code generation & /Op setting
One solution to this particular problem would be to have f() and g()
return double values instead of floats. Your particular problem
(which is common) is caused by one of the values being rounded
to float and the other not (because of the optimizer). As you
correctly observed, this causes the numbers to compare as
non-equal any time the double precision number can not be
perfectly represented as a float.

The "improve float consistency" setting will fix this problem - I've
seen it do so - so perhaps you have not specified it correctly.
It will tell the compiler to make sure that both values are rounded
to float precision, as specified in your code.
However, floating point math is inherently imprecise. There are
cases where two calculations 'should' produce identical results,
but the finite precision of floating point math means it does not.
Deal with it.

I try to avoid using float because this particular problem crops
up frequently.

Quote:

> Hi Experts,

> I noticed the following common problem when dealing with floating point
> operations in VC++. Consider the following code.

> float f() { ... }
> float g() { ... }
> ...
> if (f() == g()) ... else ...

> Now assume that the f and g functions return the same! value. However, when
> executing the if statement, the condition fails.

> Examining of the assembly shows that the result of the call to the f
> function is copied from the floating point stack in the FPU into a dword in
> memory, then g function is called, and finally, result of the g function
> still sitting on the FPU's floating point stack is compared to the result
> stored in dword in memory. When the 32bit representation stored in dword
> differs from the 80bit representation on the stack, the comparison fails
> even though the "float" values are the same... (same applied to 64bit
> doubles)

> This is a serious and I expect common issue. I hate ugly code and don't want
> to resort to tests like if (f() - g() <= ALMOST_NOTHING) ... neither do I
> want to create temporary variables to hold results of the two function calls
> just to strip down the extra bits (this could also collide with the
> optimizer). So, I was looking for a project setting to control this aspect
> of the code generation in VC++. Really, all I need is to guarantee the same
> precision for the two return values (I don't care whether both are copied
> into dwords or kept on the FPU stack which is faster and shorter, as long as
> they are the same and the comparison works).

> I found the /Op setting to "improve floating-point consistency". I though it
> was just what I was looking for but it turned out this setting does not
> affect the above code.

> Are you guys aware of any other compiler setting? Or at least an elegant way
> to deal with this in VC++? (It seems that VB by default converts floating
> point
> results to either float or double and that it actually has a switch to
> disable this to produce tighter and faster but possibly failing! code. I am
> not a VB expert but would be surprised if VB had such an option and VC++ did
> not.)

> Thanks for any advise,

> Peter

--
.Bruce Dawson, Humongous Entertainment.
http://www.humongous.com/


Sat, 16 Nov 2002 03:00:00 GMT  
 VC++ floating point code generation & /Op setting

Hi guys,

Thanks everyone for their replies.

Paul, I am aware of problems when dealing with floating point numbers
and your suggestion of "comparing with tolerance" will definitely solve the
problem. But I am thinking that in this case, the compiler should take care
of it. (Because of the finite precision, a+b may be equal to a etc. but
I think a should always equal to a. It's to do with the compiler using
different
number of bits 80 vs 32 or 64 for operands rather than with number
representation and finite precision as such.)

Bruce, when I turned on the "improve floating point consistency" and when
it did not help, I had a look whether the options made any difference
whatsoever to the generated code. It did in other parts of the code but did
not affect this particular case. I think (could be wrong of course) that it
affects only those cases, when the result is stored in a variable. In which
case, it doesn't optimize the code but reloads values via memory or
registers so that they get the correct number of bits. For this reason, I
was
wondering whether there is another compiler option.

I "fixed" the problem by changing:

        if (f() == g()) ...

to

        float a = f(), b = g();
        if (a == b) ...

Going via variables fixes this particular case.

Bruce, also, I did not try but I think there would be the same problem
even of doubles where used instead of floats i.e. the problem would be
64 bits vs 80 bits instead of 32 vs 80.

Peter

PS: One last thing, if I get a spare minute, I will make a small test case
to confirm this phenomenon but right now I am really flat out...

Quote:
> > I noticed the following common problem when dealing with floating point
> > operations in VC++. Consider the following code.

> > float f() { ... }
> > float g() { ... }
> > ...
> > if (f() == g()) ... else ...

> > Now assume that the f and g functions return the same! value. However,
when
> > executing the if statement, the condition fails.

> > Examining of the assembly shows that the result of the call to the f
> > function is copied from the floating point stack in the FPU into a dword
in
> > memory, then g function is called, and finally, result of the g function
> > still sitting on the FPU's floating point stack is compared to the
result
> > stored in dword in memory. When the 32bit representation stored in dword
> > differs from the 80bit representation on the stack, the comparison fails
> > even though the "float" values are the same... (same applied to 64bit
> > doubles)

> > This is a serious and I expect common issue. I hate ugly code and don't
want
> > to resort to tests like if (f() - g() <= ALMOST_NOTHING) ... neither do
I
> > want to create temporary variables to hold results of the two function
calls
> > just to strip down the extra bits (this could also collide with the
> > optimizer). So, I was looking for a project setting to control this
aspect
> > of the code generation in VC++. Really, all I need is to guarantee the
same
> > precision for the two return values (I don't care whether both are
copied
> > into dwords or kept on the FPU stack which is faster and shorter, as
long as
> > they are the same and the comparison works).

> > I found the /Op setting to "improve floating-point consistency". I
though it
> > was just what I was looking for but it turned out this setting does not
> > affect the above code.

> > Are you guys aware of any other compiler setting? Or at least an elegant
way
> > to deal with this in VC++? (It seems that VB by default converts
floating
> > point
> > results to either float or double and that it actually has a switch to
> > disable this to produce tighter and faster but possibly failing! code. I
am
> > not a VB expert but would be surprised if VB had such an option and VC++
did
> > not.)



Sun, 17 Nov 2002 03:00:00 GMT  
 VC++ floating point code generation & /Op setting
If "improve floating point consistency" doesn't fix this case then you
should report this as a bug. It should be easy to make a tiny test
case with two files that demonstrates the problem. You can report
the bug to:

 http://support.microsoft.com/support/visualc/report/default.asp

There is not another compiler option to fix this, other than
disabling optimizations completely.

You will not encounter this problem with doubles - I guarantee
it. The reason is that the VC++ startup code sets the FPU
internal precision to 64 bits, so all results are rounded to
double. Therefore there will never be any conflict between
64 and 80 bit precision because the 80-bit numbers are
always rounded to 64 bits.
If you wanted to you could use _controlfp() to
set the rounding to 32 bits, and that would solve your problem.
However that would be a fairly drastic and dramatic solution.

My preference is to use double variables and return values as
much as possible - that solves the problem.

Quote:

> Hi guys,

> Thanks everyone for their replies.

> Paul, I am aware of problems when dealing with floating point numbers
> and your suggestion of "comparing with tolerance" will definitely solve the
> problem. But I am thinking that in this case, the compiler should take care
> of it. (Because of the finite precision, a+b may be equal to a etc. but
> I think a should always equal to a. It's to do with the compiler using
> different
> number of bits 80 vs 32 or 64 for operands rather than with number
> representation and finite precision as such.)

> Bruce, when I turned on the "improve floating point consistency" and when
> it did not help, I had a look whether the options made any difference
> whatsoever to the generated code. It did in other parts of the code but did
> not affect this particular case. I think (could be wrong of course) that it
> affects only those cases, when the result is stored in a variable. In which
> case, it doesn't optimize the code but reloads values via memory or
> registers so that they get the correct number of bits. For this reason, I
> was
> wondering whether there is another compiler option.

> I "fixed" the problem by changing:

>         if (f() == g()) ...

> to

>         float a = f(), b = g();
>         if (a == b) ...

> Going via variables fixes this particular case.

> Bruce, also, I did not try but I think there would be the same problem
> even of doubles where used instead of floats i.e. the problem would be
> 64 bits vs 80 bits instead of 32 vs 80.

> Peter

> PS: One last thing, if I get a spare minute, I will make a small test case
> to confirm this phenomenon but right now I am really flat out...

> > > I noticed the following common problem when dealing with floating point
> > > operations in VC++. Consider the following code.

> > > float f() { ... }
> > > float g() { ... }
> > > ...
> > > if (f() == g()) ... else ...

> > > Now assume that the f and g functions return the same! value. However,
> when
> > > executing the if statement, the condition fails.

> > > Examining of the assembly shows that the result of the call to the f
> > > function is copied from the floating point stack in the FPU into a dword
> in
> > > memory, then g function is called, and finally, result of the g function
> > > still sitting on the FPU's floating point stack is compared to the
> result
> > > stored in dword in memory. When the 32bit representation stored in dword
> > > differs from the 80bit representation on the stack, the comparison fails
> > > even though the "float" values are the same... (same applied to 64bit
> > > doubles)

> > > This is a serious and I expect common issue. I hate ugly code and don't
> want
> > > to resort to tests like if (f() - g() <= ALMOST_NOTHING) ... neither do
> I
> > > want to create temporary variables to hold results of the two function
> calls
> > > just to strip down the extra bits (this could also collide with the
> > > optimizer). So, I was looking for a project setting to control this
> aspect
> > > of the code generation in VC++. Really, all I need is to guarantee the
> same
> > > precision for the two return values (I don't care whether both are
> copied
> > > into dwords or kept on the FPU stack which is faster and shorter, as
> long as
> > > they are the same and the comparison works).

> > > I found the /Op setting to "improve floating-point consistency". I
> though it
> > > was just what I was looking for but it turned out this setting does not
> > > affect the above code.

> > > Are you guys aware of any other compiler setting? Or at least an elegant
> way
> > > to deal with this in VC++? (It seems that VB by default converts
> floating
> > > point
> > > results to either float or double and that it actually has a switch to
> > > disable this to produce tighter and faster but possibly failing! code. I
> am
> > > not a VB expert but would be surprised if VB had such an option and VC++
> did
> > > not.)

--
.Bruce Dawson, Humongous Entertainment.
http://www.humongous.com/


Tue, 19 Nov 2002 03:00:00 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. Easy to see code generation bug with SP3 (floating point and /O2)

2. /Op compiler option -> Floating point preciscion

3. SHFileOperation(&op);op.pFrom

4. floating point rounding or floating point printing ?

5. Setting floating-point types to NAN and INF

6. Setting precision of a floating point number in an editbox

7. Floating point exactness & alternatives (summary)

8. ANSI C & floating point

9. ANSI C Standard & Floating Point

10. Optimizing Floating Point & Tartan C Compiler

11. Watcom & floating point

12. Help: Problem with comparing floating point numbers (example source code and output is given)

 

 
Powered by phpBB® Forum Software