Equality of floating-point numbers (special case)

Discussion in 'C Programming' started by Robert Latest, Apr 19, 2006.

  1. Hi guys,

    I'm sure this has been beaten to death on this newsgroup, but I can't
    find it in the CLC FAQ.

    Consider the following code:

    --------

    double x = some_value_from_somewhere;
    double y = x;

    if ((x == y) && ((x - y) == 0)) {
    puts("This is what I want");
    }

    --------

    Will the condition in the if statement always, unconditionally, and
    portably evaluate to a true value?

    I know that I normally cannot rely on testing floats for equality; I
    just wonder if this holds also when the variables in question are
    explicitly set to the same value in the source.

    I feel a bit stupid even typing this question since I can't imagine how
    x and y could possibly come out as unequal by any implementation's
    standard, but since I've been bitten quite a few times by things that
    seemed obvious but turned out to be different (for, in retrospect, very
    sensible reasons) I feel that I'd rather ask.

    Thanks,
    robert
     
    Robert Latest, Apr 19, 2006
    #1
    1. Advertising

  2. Robert Latest

    Eric Sosman Guest

    Robert Latest wrote On 04/19/06 10:06,:
    > Hi guys,
    >
    > I'm sure this has been beaten to death on this newsgroup, but I can't
    > find it in the CLC FAQ.
    >
    > Consider the following code:
    >
    > --------
    >
    > double x = some_value_from_somewhere;
    > double y = x;
    >
    > if ((x == y) && ((x - y) == 0)) {
    > puts("This is what I want");
    > }
    >
    > --------
    >
    > Will the condition in the if statement always, unconditionally, and
    > portably evaluate to a true value?


    No. The Standard permits floating-point implementations
    that support the notion of "not a number," or NaN. In IEEE
    implementations, NaN is unequal to all floating-point values,
    including itself (so `x == y' is false) and most ordinary
    arithmetic operations with NaN operands yield a NaN result
    (so `x - y' is NaN and `x - y == 0' is false).

    --
     
    Eric Sosman, Apr 19, 2006
    #2
    1. Advertising

  3. On Wed, 19 Apr 2006 10:29:15 -0400,
    Eric Sosman <> wrote
    in Msg. <1145456956.867691@news1nwk>

    > No. The Standard permits floating-point implementations
    > that support the notion of "not a number," or NaN. In IEEE
    > implementations, NaN is unequal to all floating-point values,
    > including itself (so `x == y' is false)


    Makes sense. What about the non-NaN case?

    robert
     
    Robert Latest, Apr 19, 2006
    #3
  4. Robert Latest

    Eric Sosman Guest

    Robert Latest wrote On 04/19/06 11:13,:
    > On Wed, 19 Apr 2006 10:29:15 -0400,
    > Eric Sosman <> wrote
    > in Msg. <1145456956.867691@news1nwk>
    >
    >> No. The Standard permits floating-point implementations
    >>that support the notion of "not a number," or NaN. In IEEE
    >>implementations, NaN is unequal to all floating-point values,
    >>including itself (so `x == y' is false)

    >
    >
    > Makes sense. What about the non-NaN case?


    The up-thread code was

    >>> double x = some_value_from_somewhere;
    >>> double y = x;
    >>>
    >>> if ((x == y) && ((x - y) == 0)) {
    >>> puts("This is what I want");
    >>> }


    puts() will not be called if `some_value_from_somewhere'
    is a NaN, and I think it will also remain uncalled if the
    value is an infinity. Even for finite values I think you are
    at the mercy of the implementation. Some systems compute
    intermediate values to more precision than `double' will
    hold, rounding or truncating when the value is actually
    stored. On such a system, the result could depend on just
    what the optimizer decides to do: if `some_value_from_somewhere'
    carries extra precision it is at least possible that the
    generated code might do something like

    compute_high_precision some_value_from_somewhere
    store_rounded x
    store_rounded y
    compare_to y

    .... thus re-using the extra-precise `some_value_from_somewhere'
    instead of the normally-precise `x', and the comparison could
    yield non-equal.

    Floating-point implementations have a lot of quirks, even
    today, and it is no wonder that the C committee decided not to
    try to iron them out by fiat. Thus, the specifications of F-P
    behavior in C are awfully loose, and the corner cases tend to
    yield different answers on different systems. I've heard it
    said (though I'm not enough of an F-P specialist to evaluate
    the argument) that no high-level programming language provides
    a correct implementation even of IEEE binary floating-point.

    --
     
    Eric Sosman, Apr 19, 2006
    #4
  5. On 2006-04-19, Eric Sosman <> wrote:

    > Even for finite values I think you are
    > at the mercy of the implementation.


    [...]

    > Floating-point implementations have a lot of quirks, even
    > today, and it is no wonder that the C committee decided not to
    > try to iron them out by fiat.


    [...]

    In other words: Don't compare float values. Ever. Under no
    circumstances. Be prepared that the expression

    ((double) 0) == (double) 0)

    may evaluate to 0.

    Thanks,
    robert
     
    Robert Latest, Apr 19, 2006
    #5
  6. Robert Latest

    Coos Haak Guest

    Op 19 Apr 2006 18:39:54 GMT schreef Robert Latest:

    > On 2006-04-19, Eric Sosman <> wrote:
    >
    >> Even for finite values I think you are
    >> at the mercy of the implementation.

    >
    > [...]
    >
    >> Floating-point implementations have a lot of quirks, even
    >> today, and it is no wonder that the C committee decided not to
    >> try to iron them out by fiat.

    >
    > [...]
    >
    > In other words: Don't compare float values. Ever. Under no
    > circumstances.

    Rather a bold statement, it's only for equality.
    Everyone can freely and dependently compare for less than
    or greater than. ;-)
    --
    Coos
     
    Coos Haak, Apr 19, 2006
    #6
  7. Robert Latest

    Eric Sosman Guest

    Robert Latest wrote On 04/19/06 14:39,:
    > On 2006-04-19, Eric Sosman <> wrote:
    >
    >
    >>Even for finite values I think you are
    >>at the mercy of the implementation.

    >
    >
    > [...]
    >
    >
    >> Floating-point implementations have a lot of quirks, even
    >>today, and it is no wonder that the C committee decided not to
    >>try to iron them out by fiat.

    >
    >
    > [...]
    >
    > In other words: Don't compare float values. Ever. Under no
    > circumstances. Be prepared that the expression
    >
    > ((double) 0) == (double) 0)
    >
    > may evaluate to 0.


    Well, now I think you're going overboard. Equality
    comparisons of F-P values are cause for raised eyebrows,
    but not necessarily to be shunned in every circumstance.
    For example, consider this qsort() comparator:

    int compare_doubles(const void *p, const void *q) {
    double u = *(const double*)p;
    double v = *(const double*)q;
    if (u < v) return -1;
    if (u > v) return +1;
    return 0;
    }

    There's an implicit equality comparison tucked away in
    this code, and I don't think it can be eliminated: no
    matter how the comparison function is written, it must
    be capable of returning zero. When it returns zero, it
    has, in effect, performed an equality comparison.

    --
     
    Eric Sosman, Apr 19, 2006
    #7
  8. Robert Latest

    bert Guest

    Coos Haak wrote:
    > Op 19 Apr 2006 18:39:54 GMT schreef Robert Latest:
    > > On 2006-04-19, Eric Sosman <> wrote:
    > > In other words: Don't compare float values. Ever. Under no
    > > circumstances.

    > Rather a bold statement, it's only for equality.
    > Everyone can freely and dependently compare for less than
    > or greater than. ;-)
    > --
    > Coos


    Alas, probably not so. If I recall correctly, then according to
    the strict IEEE spec, when 'x' is a NaN, the conditions (x > y),
    (x == y) and (x < y) should all be FALSE. But an optimising
    compiler may unsoundly choose to evaluate them differently.
    --
     
    bert, Apr 19, 2006
    #8
  9. On Wed, 19 Apr 2006 22:34:05 +0200, in comp.lang.c , Coos Haak
    <> wrote:

    >Op 19 Apr 2006 18:39:54 GMT schreef Robert Latest:
    >
    >> On 2006-04-19, Eric Sosman <> wrote:
    >>
    >>> Even for finite values I think you are
    >>> at the mercy of the implementation.

    >>
    >> [...]
    >>
    >>> Floating-point implementations have a lot of quirks, even
    >>> today, and it is no wonder that the C committee decided not to
    >>> try to iron them out by fiat.

    >>
    >> [...]
    >>
    >> In other words: Don't compare float values. Ever. Under no
    >> circumstances.

    >Rather a bold statement, it's only for equality.
    >Everyone can freely and dependently compare for less than
    >or greater than. ;-)


    I've seen this fail too:

    float s = some_value_retrieved_from_database;
    if (s >4.5) puts("high interest rate!");



    Mark McIntyre
    --
    "Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are,
    by definition, not smart enough to debug it."
    --Brian Kernighan
     
    Mark McIntyre, Apr 19, 2006
    #9
  10. In article <> Robert Latest <> writes:
    > double x = some_value_from_somewhere;
    > double y = x;
    >
    > if ((x == y) && ((x - y) == 0)) {
    > puts("This is what I want");
    > }

    ....
    > Will the condition in the if statement always, unconditionally, and
    > portably evaluate to a true value?


    No.

    > I feel a bit stupid even typing this question since I can't imagine how
    > x and y could possibly come out as unequal by any implementation's
    > standard,


    Consider the situation where "some_value_from_somewhere" is calculated
    in extended precision. The implementation is allowed to use that
    extended precision values in every place where "x" or "y" are used,
    or it may not. So it can happen that the "x" in "x == y" is retrieved
    in the stored precision but that the extended precision value is used
    in "y", and they possibly do not compare equal.
    --
    dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
    home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
     
    Dik T. Winter, Apr 19, 2006
    #10
  11. Robert Latest

    Naresh Guest

    Eric Sosman wrote:

    > Well, now I think you're going overboard. Equality
    > comparisons of F-P values are cause for raised eyebrows,
    > but not necessarily to be shunned in every circumstance.
    > For example, consider this qsort() comparator:
    >
    > int compare_doubles(const void *p, const void *q) {
    > double u = *(const double*)p;
    > double v = *(const double*)q;
    > if (u < v) return -1;
    > if (u > v) return +1;
    > return 0;
    > }
    >
    > There's an implicit equality comparison tucked away in
    > this code, and I don't think it can be eliminated: no
    > matter how the comparison function is written, it must
    > be capable of returning zero. When it returns zero, it
    > has, in effect, performed an equality comparison.
    >


    #include<stdio.h>

    int compare_doubles(const void *p, const void *q) {
    double u = *(const double*)p;
    double v = *(const double*)q;
    if (u < v) return -1;
    if (u > v) return +1;
    return 0;
    }

    int main(void)
    {
    float u, v;
    /* I'm using float here instead of double */

    int value;

    u = 4.50;
    v = 4.50;

    value = compare_doubles(&u, &v);

    return value;
    }

    It doesnt return 0 unless i use double u,v; in main.
    Whats is the wrong i'm doing by using float? Isnt that function should
    itself extend float to double precision and do the things?
     
    Naresh, Apr 20, 2006
    #11
  12. Robert Latest

    Naresh Guest

    Naresh wrote:
    > Eric Sosman wrote:
    >
    > > Well, now I think you're going overboard. Equality
    > > comparisons of F-P values are cause for raised eyebrows,
    > > but not necessarily to be shunned in every circumstance.
    > > For example, consider this qsort() comparator:
    > >
    > > int compare_doubles(const void *p, const void *q) {
    > > double u = *(const double*)p;
    > > double v = *(const double*)q;
    > > if (u < v) return -1;
    > > if (u > v) return +1;
    > > return 0;
    > > }
    > >
    > > There's an implicit equality comparison tucked away in
    > > this code, and I don't think it can be eliminated: no
    > > matter how the comparison function is written, it must
    > > be capable of returning zero. When it returns zero, it
    > > has, in effect, performed an equality comparison.

    >


    Oh sorry, I misunderstood the statement. "..and I don't think it can be
    eliminated: no
    matter how the comparison function is written, it must be capable of
    returning zero...."
     
    Naresh, Apr 20, 2006
    #12
  13. Robert Latest

    Sjouke Burry Guest

    Naresh wrote:
    > Eric Sosman wrote:
    >
    >
    >> Well, now I think you're going overboard. Equality
    >>comparisons of F-P values are cause for raised eyebrows,
    >>but not necessarily to be shunned in every circumstance.
    >>For example, consider this qsort() comparator:
    >>
    >> int compare_doubles(const void *p, const void *q) {
    >> double u = *(const double*)p;
    >> double v = *(const double*)q;
    >> if (u < v) return -1;
    >> if (u > v) return +1;
    >> return 0;
    >> }
    >>
    >>There's an implicit equality comparison tucked away in
    >>this code, and I don't think it can be eliminated: no
    >>matter how the comparison function is written, it must
    >>be capable of returning zero. When it returns zero, it
    >>has, in effect, performed an equality comparison.
    >>

    >
    >
    > #include<stdio.h>
    >
    > int compare_doubles(const void *p, const void *q) {
    > double u = *(const double*)p;
    > double v = *(const double*)q;
    > if (u < v) return -1;
    > if (u > v) return +1;
    > return 0;
    > }
    >
    > int main(void)
    > {
    > float u, v;
    > /* I'm using float here instead of double */
    >
    > int value;
    >
    > u = 4.50;
    > v = 4.50;
    >
    > value = compare_doubles(&u, &v);
    >
    > return value;
    > }
    >
    > It doesnt return 0 unless i use double u,v; in main.
    > Whats is the wrong i'm doing by using float? Isnt that function should
    > itself extend float to double precision and do the things?
    >

    You are pointing to floats and compare them
    as doubles,of course they are not equal.
    Both pointers as used add 4 random
    bytes to themselfs.(assuming 4byte float and
    8 byte doubles).
    If there had been cleared bytes behind them,
    you might even find them equal(and get bitten
    later on).
     
    Sjouke Burry, Apr 20, 2006
    #13
  14. Robert Latest

    Patrick Guest

    Branching off of what Eric Sosman described, you could try the same
    thing but with an explicit comparison of the difference with an error
    constant. It would look something like this:

    ------------------------------
    #define EPSILON 0.000001
    /* ... */
    if ( abs(y-x) < EPSILON )
    puts("This is what I want");

    ----------------------------

    This way, you can define how many decimal digits of equality you want
    in the comparison, and in my experiance, the less-than operator is much
    more stable than the equality operator, at least with floating point
    numbers.
     
    Patrick, Apr 20, 2006
    #14
  15. Robert Latest

    P.J. Plauger Guest

    "Patrick" <> wrote in message
    news:...

    > Branching off of what Eric Sosman described, you could try the same
    > thing but with an explicit comparison of the difference with an error
    > constant. It would look something like this:
    >
    > ------------------------------
    > #define EPSILON 0.000001
    > /* ... */
    > if ( abs(y-x) < EPSILON )
    > puts("This is what I want");
    >
    > ----------------------------
    >
    > This way, you can define how many decimal digits of equality you want
    > in the comparison, and in my experiance, the less-than operator is much
    > more stable than the equality operator, at least with floating point
    > numbers.


    Such an approach is *not* suitable for ordering floating-point values,
    as in bsearch and qsort. You can end up with the situation where a == b
    and b == c, but a != c. You need a strict weak ordering which is just
    not all that hard to create for floating-point values. NaNs are the only
    real trouble spot.

    P.J. Plauger
    Dinkumware, Ltd.
    http://www.dinkumware.com


    P.J. Plauger
    Dinkumware, Ltd.
    http://www.dinkumware.com
     
    P.J. Plauger, Apr 20, 2006
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. H aka N
    Replies:
    15
    Views:
    15,691
    Ben Jones
    Mar 2, 2006
  2. Motaz Saad
    Replies:
    7
    Views:
    6,503
  3. Replies:
    3
    Views:
    317
  4. Saraswati lakki
    Replies:
    0
    Views:
    1,356
    Saraswati lakki
    Jan 6, 2012
  5. teeshift
    Replies:
    2
    Views:
    268
    Chris Pearl
    Dec 1, 2006
Loading...

Share This Page