Wrong results when comparing negative double variables in an if statement

Discussion in 'C Programming' started by John, Apr 23, 2004.

  1. John

    John Guest

    Hi,

    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?

    #include <ansi_c.h>

    void main (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

    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);
    }

    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.

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

    Thanks in advance,
    John.
    John, Apr 23, 2004
    #1
    1. Advertising

  2. John

    Eric Sosman Guest

    Re: Wrong results when comparing negative double variables in an ifstatement

    John wrote:
    >
    > Hi,
    >
    > 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?


    Apparently not, indeed. This is Question 14.1 in the
    comp.lang.c Frequently Asked Questions (FAQ) list

    http://www.eskimo.com/~scs/C-faq/top.html

    .... and the next time somebody tells you that everybody's
    "computer-literate" nowadays, you can cite the frequency
    of this question as evidence to the contrary.

    --
    Eric Sosman, Apr 23, 2004
    #2
    1. Advertising

  3. >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
    Gordon Burditt, Apr 23, 2004
    #3
  4. Re: Wrong results when comparing negative double variables in an ifstatement

    On Fri, 23 Apr 2004, John wrote:

    > Hi,
    >
    > 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?


    ANSI C is fine. Your assumption about comparing double variables is wrong.

    Thing about this, there are infinite numbers between 0 and 1. Therefore
    there is no way a computer can represent all numbers between 0 and 1 let
    alone all real numbers in a larger range. This means that there will be
    some numbers that are not represented. If I have:

    double a = 2;
    a += 0.01;
    a -= 0.01;

    Maybe 2.01 is a number that your compiler cannot represent. It might
    decide to round up to the next closest number. When you decrement you
    probably get a number that cannot be represented so it rounds up to the
    next closet number. Now a will equal 2.00000000000001. This is called
    representation error.

    When you print them out, printf will only print 6 digits. So it looks like
    a is still 2.000000 but it has just trimmed off the representation error
    from the display. If you did something like:

    printf("%020.20f\n", a);

    You'd see the real value of a. In <float.h> are macros to help with this
    problem. Rather than comparing a to b you would look at the different
    between a and b. If the different is smaller than EPSILON then you should
    assume they are close enough to be called equal.

    > #include <ansi_c.h>
    >
    > void main (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
    >
    > 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);
    > }
    >
    > 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.
    >
    > I would be grateful for any solutions or suggestions to this problem
    > so that I can process *all* fractions correctly.
    >
    > Thanks in advance,
    > John.
    >


    --
    Send e-mail to: darrell at cs dot toronto dot edu
    Don't send e-mail to
    Darrell Grainger, Apr 23, 2004
    #4
  5. Re: Wrong results when comparing negative double variables in anif statement

    John wrote:

    > Hi,
    >
    > 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?
    >
    > #include <ansi_c.h>

    The above is *NOT* an ANSI C header. It is non-standard.
    >
    > void main (void)


    It is invalid in a hosted implementation (which anything running under
    Window is) for main to have *any* return type other than 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);


    Please check the FAQ before posting. In particular, read the answers in
    section 14 (floating point) <http://www.eskimo.com/~scs/C-faq/s14.html>.
    If that does not suffice, remember that testing floating point numbers
    for equality, which you are doing surreptitiously, is infested with
    traps for the unwary.
    Martin Ambuhl, Apr 24, 2004
    #5
  6. [snips]

    On Fri, 23 Apr 2004 19:58:34 -0400, Martin Ambuhl wrote:

    >> void main (void)

    >
    > It is invalid in a hosted implementation (which anything running under
    > Window is) for main to have *any* return type other than void.


    Want to try that one again? Like, maybe, by suggesting a return type of,
    say, int? :)
    Kelsey Bjarnason, Apr 24, 2004
    #6
  7. John

    John Guest

    Hi,

    Thank you all for your help. I'll represent all my numbers as integers
    and only convert them to floating point numbers after processing.

    Cheers,
    John.
    John, Apr 24, 2004
    #7
  8. John

    Eric Sosman Guest

    Re: Wrong results when comparing negative double variables in an ifstatement

    John wrote:
    >
    > Hi,
    >
    > Thank you all for your help. I'll represent all my numbers as integers
    > and only convert them to floating point numbers after processing.


    You have just discovered that a screwdriver is not a
    claw hammer, which is useful knowledge. You have decided
    therefore to drive screws with your hammer, which is a sub-
    optimal response ...

    --
    Eric Sosman, Apr 26, 2004
    #8
  9. Re: Wrong results when comparing negative double variables in an if statement

    In article <c6caje$aht8h$-berlin.de>, Martin Ambuhl <> writes:
    >
    > It is invalid in a hosted implementation (which anything running under
    > Window is) ...


    A great many Windows programs run in a freestanding implementation
    known as "GUI mode". Such programs enter in a function named WinMain.

    This freestanding implementation is itself implemented under a
    hosted implementation, but a Windows GUI-mode program's main is
    part of the implementation, not part of the user program.

    Of course, if you're writing a Windows program, and it includes a
    main, you're almost certainly writing to the hosted implementation
    and that main should conform to the spec.

    --
    Michael Wojcik

    Dude, it helps to be smart if you're gonna be mean.
    -- Darby Conley
    Michael Wojcik, Apr 26, 2004
    #9
  10. John

    John Guest

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

    Eric Sosman <> wrote in message news:<>...
    > John wrote:
    > >
    > > Hi,
    > >
    > > Thank you all for your help. I'll represent all my numbers as integers
    > > and only convert them to floating point numbers after processing.

    >
    > You have just discovered that a screwdriver is not a
    > claw hammer, which is useful knowledge. You have decided
    > therefore to drive screws with your hammer, which is a sub-
    > optimal response ...


    That's a good analogy, but it's how the desktop calculators and
    checkout cash registers do it. The decimal point is never typed in
    although it appears on the receipt and the display in its fixed
    position. I only need two decimal places so I think the hammer will
    suffice. :)
    John, Apr 27, 2004
    #10
  11. John

    Villy Kruse Guest

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

    On 27 Apr 2004 01:44:51 -0700,
    John <> wrote:


    > Eric Sosman <> wrote in message news:<>...
    >> John wrote:
    >> >
    >> > Hi,
    >> >
    >> > Thank you all for your help. I'll represent all my numbers as integers
    >> > and only convert them to floating point numbers after processing.

    >>
    >> You have just discovered that a screwdriver is not a
    >> claw hammer, which is useful knowledge. You have decided
    >> therefore to drive screws with your hammer, which is a sub-
    >> optimal response ...

    >
    > That's a good analogy, but it's how the desktop calculators and
    > checkout cash registers do it. The decimal point is never typed in
    > although it appears on the receipt and the display in its fixed
    > position. I only need two decimal places so I think the hammer will
    > suffice. :)


    The cash register works in fixed point decimal, a common data type seen
    in COBOL but not normaly supported by the C language. I do beleive
    that the decimal point *is* typed in when using those machines, at least
    on general purpose adding machines.


    Villy
    Villy Kruse, Apr 28, 2004
    #11
  12. John

    John Guest

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

    My parents own a retail business and we never type in a decimal point
    on any of our cash registers, although such a key is present on some
    models, even though it need not be used. It's unnecessary for any
    currency that has 100 pence/cents/etc to the pound/dollar/euro etc.
    It's faster to type in '246' rather than '2.46' (one less key to
    press). That trick meets my requirements although it woundn't work for
    fractions that have a variable number of decimal places.

    John.

    Villy Kruse <> wrote in message news:<>...
    > On 27 Apr 2004 01:44:51 -0700,
    > John <> wrote:
    >
    >
    > > Eric Sosman <> wrote in message news:<>...
    > >> John wrote:
    > >> >
    > >> > Hi,
    > >> >
    > >> > Thank you all for your help. I'll represent all my numbers as integers
    > >> > and only convert them to floating point numbers after processing.
    > >>
    > >> You have just discovered that a screwdriver is not a
    > >> claw hammer, which is useful knowledge. You have decided
    > >> therefore to drive screws with your hammer, which is a sub-
    > >> optimal response ...

    > >
    > > That's a good analogy, but it's how the desktop calculators and
    > > checkout cash registers do it. The decimal point is never typed in
    > > although it appears on the receipt and the display in its fixed
    > > position. I only need two decimal places so I think the hammer will
    > > suffice. :)

    >
    > The cash register works in fixed point decimal, a common data type seen
    > in COBOL but not normaly supported by the C language. I do beleive
    > that the decimal point *is* typed in when using those machines, at least
    > on general purpose adding machines.
    >
    >
    > Villy
    John, May 5, 2004
    #12
    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. prem_eda
    Replies:
    5
    Views:
    7,852
    Pieter Hulshoff
    Oct 11, 2004
  2. Sydex
    Replies:
    12
    Views:
    6,487
    Victor Bazarov
    Feb 17, 2005
  3. Peter Ammon

    Most negative double value

    Peter Ammon, Feb 19, 2004, in forum: C Programming
    Replies:
    30
    Views:
    1,282
    Christian Bau
    Feb 25, 2004
  4. Michael Mair

    Typecast long double->double seems to go wrong

    Michael Mair, May 24, 2004, in forum: C Programming
    Replies:
    4
    Views:
    657
    Michael Mair
    May 24, 2004
  5. Jamie Sutherland

    Comparing a Datagrid items to a datareader results - Help Please

    Jamie Sutherland, Apr 13, 2004, in forum: ASP .Net Datagrid Control
    Replies:
    0
    Views:
    104
    Jamie Sutherland
    Apr 13, 2004
Loading...

Share This Page