views:

106

answers:

5

If foo is of float type, is the following expression valid/recommended?

(0.0f == foo * float(0))

Will it have the expected (mathematical) value regardless of foo's value?

Does the C++ standard defines the behavior or is it implementation specific?

+3  A: 

AFAIK, It won't necessarily, tt could also end up very close to 0.

It is generally best to compare against an epsilon. I use a function like this for doing such comparisons:

float EpsilonEqual( float a, float b, float epsilon )
{
    return fabsf( a - b ) < epsilon;
}
Goz
@Goz: fmodf or fabs?
Armen Tsirunyan
@Armen: You are quite right its fabsf :)
Goz
IEEE 754 mandates that -0.0f == +0.0f, even though the bit values are different.
Michael Borgwardt
@Michael: Fair enough. Doesn't detract from the point though. I'll remove the reference however.
Goz
+2  A: 

Well, first off it isn't really a matter of the C++ standard. Rather what is at issue is your floating-point model standard (most likely IEEE).

For IEEE floats, that is probably safe, as float(0) should result in the same number as 0.0f, and that multiplied by any other number should also be 0.0f.

What isn't really safe is doing other floating point ops (eg: adds and subtracts with non-whole numbers) and checking them against 0.0f.

T.E.D.
Multiplying any finite IEEE value by zero will give zero. If `foo` is infinity or NaN, then the multiplication result is NaN, and the comparison result is false.
Mike Seymour
@Mike Seymour - Good point. Perhaps that line was meant to be a check that foo is a valid float value.
T.E.D.
A: 

With that particular statement, you can be pretty sure the result will be 0 and the comparison be true - I don't think the C++ standard actually proscribes it, but any reasonable implementation of floating point types will have 0 work like that.

However, for most other calculations, the result cannot be expected to be exactly equal to a literal of the mathematically correct result:

Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and instead I get a weird result like 0.30000000000000004?

Because internally, computers use a format (binary floating-point) that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.

When the code is compiled or interpreted, your “0.1” is already rounded to the nearest number in that format, which results in a small rounding error even before the calculation happens.

Read The Floating-Point Guide for detailed explanations and how to do comparisons with expected values correctly.

Michael Borgwardt
A: 

I just read this article in msdn about the /fp option in VisualStudio link text

Expression optimizations that are invalid for special values (NaN, +infinity, -infinity, +0, -0) will not be allowed. The optimizations x-x => 0, x*0 => 0, x-0 => x, x+0 => x, and 0-x => -x are all invalid for various reasons (see IEEE 754 and the C99 standard).

MarcoH
I'm guessing that the comment here is only referring to the fact that x*0 is NaN if x is NaN.
hobbs
+1  A: 

NaNs and Infinites can screw up such comparisions, as others have already mentioned.

However, there is further pitfall: in C++ you can not rely on a compile time expression of float type, comparing equal to the same expression evaluated at run time.

The reason for that is that C++ allows extended precision for fp computations, in any willy-nilly way. Example:

#include <iostream>

// This provides sufficent obfuscation so that g++ doesn't just inline results.
bool obfuscatedTrue() { return true; }

int main()
{
    using namespace std;

    double const    a   = (obfuscatedTrue()? 3.0 : 0.3);
    double const    b   = (obfuscatedTrue()? 7.0 : 0.7);
    double const    c   = a/b;

    cout << (c == a/b? "OK." : "\"Wrong\" comparision result.") << endl;
}

Results with one particular compiler:

C:\test> g++ --version | find "++"
g++ (TDM-2 mingw32) 4.4.1

C:\test> g++ fp_comparision_problem.cpp & a
"Wrong" comparision result.

C:\test> g++ -O fp_comparision_problem.cpp & a
OK.

C:\test> _

Cheers & hth.,

– Alf

Alf P. Steinbach