Re: Wrong results when comparing negative double variables in an if statement

From: Gordon Burditt (gordonb.4lxna_at_burditt.org)
Date: 04/23/04


Date: 23 Apr 2004 20:14:33 GMT


>I encountered a strange problem while debugging C code for a
>Windows-based application in LabWindows CVI V5.5, which led me to
>write the test code below. I tried this code with a different compiler
>and got the same erroneous result on two different PCs (with OS Win98
>& Win98SE), so it appears to be a problem with ANSI C. I thought that
>negative double variables could be compared as easily and *reliably*
>as integers, but apparently not?

Rounding error. If you're going to use floating-point numbers,
learn to live with it. And it's not only *NEGATIVE* numbers
that have the problem.

>#include <ansi_c.h>

Non-standard include file.

>
>void main (void)

main returns int, not void!

>{
>double a = -2.0, b = -2.0;
>
>if (a > b)
> printf("a is greater than b because a is %f and b is %f\n", a, b);
>else
> printf("a is not greater than b because a is %f and b is %f\n", a,
>b);
>
>a -= 0.01; // decrease value of a by 0.01
>a += 0.01; // restore original value of a by increasing it by 0.01

No, you are NOT guaranteed that this will restore a to the original
value. There is no exact value of 0.01 in binary floating point.

>
>if (a > b)
> printf("a is greater than b because a is %f and b is %f\n", a, b);
>else
> printf("a is not greater than b because a is %f and b is %f\n", a,
>b);

Print the numbers with unreasonably large precision, say %200.100f,
and you'll see what is going on. Also try printing 0.01 with
unreasonably large precision. Note that you're doing this for
debugging purposes, not because floating-point numbers have hundreds
of digits of accuracy, which they don't on any real machines I
have encountered, barring use of bignum packages which aren't
native C types.

>}
>
>The output as copied from the emulated DOS window is:
>
>a is not greater than b because a is -2.000000 and b is -2.000000
>a is greater than b because a is -2.000000 and b is -2.000000
>
>If I decrement and then increment a by 0.001, everything is fine, so
>it doesn't look like there is a problem with the small magnitude of
>the fractions.

There is no exact value of 0.001 in binary floating point, either.

>I would be grateful for any solutions or suggestions to this problem
>so that I can process *all* fractions correctly.

Rounding error. Learn to live with it. (Very few decimal numbers
other than exact integers have exact representations in binary
floating point, a few exceptions being .5, .25, .75, .125, .375,
.625, and .875.) You might want to do this by explicitly rounding the
number yourself, and do NOT depend on what happens at the
exactly-half-way points.

Money is best represented as an integer quantity of the smallest
unit of currency you have to deal with (which might be cents in the
USA, or might be ten-thousandths of cents if you're an electric
company setting a price per kilowatt-hour to bill customers). You
can store this in an integer or floating type as appropriate for
the application. Bill Gates wouldn't want to use a 32-bit unsigned
long in cents (overflows at slightly under $43 million) for his net
worth, but it's fine for your average kid running a lemonade stand.
double or (for C99) long long might work well for all but the biggest
companies/governments.

                                                Gordon L. Burditt



Relevant Pages

  • Re: Float comparison
    ... Oh, it exists, but not in that floating representation. ... Keith has already mentioned the need to do an error analysis if you want to know what the possible error. ... I know of code which carefully uses doubles to do integer arithmetic, staying within the range where integers can be represented exactly, in order to use the greater range of exact integral values that a double can represent on that specific implementation than an int. ... So either integer types cannot store exact values and you need to do a full error analysis to determine the range of values they might represent or floating point variables can store exact values which are exactly the mathematically correct values the program is intended to store. ...
    (comp.lang.c)
  • Re: Cant get Access to run a query with a time field
    ... Since the user enters an exact value, why isn't it saved to the ... Second, a date time value is a floating point value, ... >> Vanderghast, Access MVP ...
    (microsoft.public.access.queries)
  • Re: for problem...
    ... DC>>Removing the braces should not make any difference. ... since '0.01' is never an exact value. ... in the *nature* of floating point operations. ... with the roundoff error 'contained' ...
    (comp.lang.tcl)
  • Re: (* 2.4 3) => 7.2000003 WTF?! Lets Fix Lisp! Noob Programming Challenge
    ... Then don't use frickin floating point!! ... designed to give exact results of calculations. ... Lisp for your enjoyment. ...
    (comp.lang.lisp)
  • Re: How do I see images in outline view?
    ... floating window on use View> Toolbars> Animation Effects. ... 84a1162d.0404191555.ad5702e@posting.google.com, "Dr Mike" ...
    (microsoft.public.mac.office.powerpoint)