Beginner question: Precision of floating point arithmetic...

Discussion in 'C Programming' started by Shawn, Jul 14, 2004.

  1. Shawn

    Shawn Guest

    Hello all,
    I apologize as I am sure this has probably been dealth with before...
    but I am doing an exercise from "Practical C Programming" and I have
    been unable to get it to work perfectly due to problems with floating
    point arithmetic and I am looking for a way to solve it. See the code
    below...
    Given a certain amount of change (below $1.00) the program will tell
    you how many of each coin you will need to get that amount. The
    program is "working" in that the logic appears correct and it DOES
    work for some numbers, but for others, it is not. The problem appears
    to be that 0.01 as I see it, is not being represented in memory.
    I have done some searching online and I am sure this is a common
    problem but I just can't seem to find the workaround...

    Thank you for all your help...

    Shawn

    #include <stdio.h>

    int main()
    {
    char input[100];
    float total_input, running_total;
    int quarters, nickels, dimes, pennies;

    /* Zero out all the variables */
    quarters = nickels = dimes = pennies = 0;
    total_input = running_total = 0;

    /* Get the necessary amount of change */
    printf("Enter the total amount of change, less than $1.00: ");
    fgets(input, sizeof(input), stdin);
    sscanf(input, "%f", &total_input);

    /* Loop until we get a sane amount */
    while (total_input >= 1.00 || total_input <= 0.00) {
    printf("Total is not between $0.00 and $1.00.\n");
    printf("Enter the total amount of change, less than
    $1.00: ");
    fgets(input, sizeof(input), stdin);
    sscanf(input, "%f", &total_input);
    }

    /* Store in another variable so we can use it */
    running_total = total_input;

    while (running_total >= 0.25) {
    ++quarters;
    running_total -= 0.25;
    }
    while (running_total >= 0.10) {
    ++dimes;
    running_total -= 0.10;
    }
    while (running_total >= 0.05) {
    ++nickels;
    running_total -= 0.05;
    }
    while (running_total >= 0.01) {
    ++pennies;
    running_total -= 0.01;
    }

    printf("In order to get $%.2f in change, you will need:\n",
    total_input);
    printf("%d quarters,\n", quarters);
    printf("%d dimes,\n", dimes);
    printf("%d nickels,\n", nickels);
    printf("%d pennies\n", pennies);

    return(0);
    }
    Shawn, Jul 14, 2004
    #1
    1. Advertising

  2. Shawn

    Eric Sosman Guest

    Shawn wrote:
    > Hello all,
    > I apologize as I am sure this has probably been dealth with before...
    > but I am doing an exercise from "Practical C Programming" and I have
    > been unable to get it to work perfectly due to problems with floating
    > point arithmetic and I am looking for a way to solve it. See the code
    > below...
    > Given a certain amount of change (below $1.00) the program will tell
    > you how many of each coin you will need to get that amount. The
    > program is "working" in that the logic appears correct and it DOES
    > work for some numbers, but for others, it is not. The problem appears
    > to be that 0.01 as I see it, is not being represented in memory.
    > I have done some searching online and I am sure this is a common
    > problem but I just can't seem to find the workaround...


    First, the question has, as you suspect, arisen before.
    In fact, it arises frequently, and therefore has a place in
    the comp.lang.c Frequently Asked Questions (FAQ) list

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

    Start with Question 14.1, and then look at 14.4 and 14.5.

    Once you've digested that, you'll have realized that
    floating-point arithmetic is trickier than it first appears.
    Floating-point is very good at dealing with proportions and
    ratios and logarithms and the like, but is not well-suited
    to counting problems -- problems involving discrete "things,"
    if you like. So what's the work-around? Well, can you think
    of a way to restate your original problem in terms of discrete
    indivisible units instead of fractions of something-or-other?
    Hint: What should your program do if someone asks for $0.14159
    in change?

    --
    Eric Sosman, Jul 14, 2004
    #2
    1. Advertising

  3. Shawn

    Malcolm Guest

    "Shawn" <> wrote in message
    >
    > #include <stdio.h>
    >
    > int main()
    > {
    > char input[100];
    > float total_input, running_total;
    > int quarters, nickels, dimes, pennies;
    >
    > /* Zero out all the variables */
    > quarters = nickels = dimes = pennies = 0;
    > total_input = running_total = 0;
    >
    > /* Get the necessary amount of change */
    > printf("Enter the total amount of change, less than $1.00: ");
    > fgets(input, sizeof(input), stdin);
    > sscanf(input, "%f", &total_input);
    >

    You want to check your return from sscanf().
    >
    > /* Loop until we get a sane amount */
    > while (total_input >= 1.00 || total_input <= 0.00) {
    > printf("Total is not between $0.00 and $1.00.\n");
    > printf("Enter the total amount of change, less than
    > $1.00: ");
    > fgets(input, sizeof(input), stdin);
    > sscanf(input, "%f", &total_input);
    > }
    >
    > /* Store in another variable so we can use it */
    > running_total = total_input;
    >
    > while (running_total >= 0.25) {
    > ++quarters;
    > running_total -= 0.25;
    > }
    >

    Here's your problem. Floating point representation is not exact, so if the
    user enters 0.50 theres no guarantee that this won't be represented
    internally as 0.4999, which will mess up your logic.
    In fact all floating point units use a binary base, so 0.50 and 0.25 can be
    represented exactly, but 0.1 cannot be. So the problem isn't here but in the
    similar block of code for the dimes, below.
    >
    > while (running_total >= 0.10) {
    > ++dimes;
    > running_total -= 0.10;
    > }
    > while (running_total >= 0.05) {
    > ++nickels;
    > running_total -= 0.05;
    > }
    > while (running_total >= 0.01) {
    > ++pennies;
    > running_total -= 0.01;
    > }
    >
    > printf("In order to get $%.2f in change, you will need:\n",
    > total_input);
    > printf("%d quarters,\n", quarters);
    > printf("%d dimes,\n", dimes);
    > printf("%d nickels,\n", nickels);
    > printf("%d pennies\n", pennies);
    >
    > return(0);
    > }


    >

    The solution is to convert your float value, input, into an integer number
    of pennies (I thought you Americans used cents, but that's by the by).

    To do this, multiply the float value by 100, then round by adding 0.5 and
    calling floor(). Just multiplying by 100 risks the inaccuracy problem
    because a value of x.9999 will be rounded down.
    Malcolm, Jul 14, 2004
    #3
  4. >I apologize as I am sure this has probably been dealth with before...
    >but I am doing an exercise from "Practical C Programming" and I have
    >been unable to get it to work perfectly due to problems with floating
    >point arithmetic and I am looking for a way to solve it. See the code
    >below...
    >Given a certain amount of change (below $1.00) the program will tell
    >you how many of each coin you will need to get that amount. The


    Use integer quantities of cents. You may use a floating-point variable
    to store this if you want.

    >program is "working" in that the logic appears correct and it DOES
    >work for some numbers, but for others, it is not. The problem appears
    >to be that 0.01 as I see it, is not being represented in memory.


    There is no exact representation for 0.01 in binary floating point, nor
    is there for most non-integer decimal numbers. (Think about representing
    1/3 exactly in decimal). There *IS* a representation, just not an
    exact one.

    >I have done some searching online and I am sure this is a common
    >problem but I just can't seem to find the workaround...


    It's not exact. Learn to live with it. The world is also an analog
    world with all sorts of floating-point measurements, and no measurement
    is exact. Comparing two floating-point numbers for exact equality
    is hazardous. How close two floating-point numbers have to be
    (either by ratio or by absolute difference) generally should be
    APPLICATION-DEPENDENT, and NOT depend on details like the number
    of significant digits being used in the implementation. Example:
    the GPS coordinates of two telephone poles are considered identical
    (and to refer to the same pole) if they are within 20 feet of each
    other, because GPS cannot reliably measure distances more accurately
    than that, and besides, phone companies don't place poles that close
    to each other.

    One approach for money is to use the integer value 1 to represent the smallest
    amount of money of interest (which for some applications might be a tenth
    or thousandth of a cent in the USA). Of course, printing such a value
    on checks needs to be done carefully.

    Gordon L. Burditt
    Gordon Burditt, Jul 14, 2004
    #4
  5. "Malcolm" <> writes:
    [...]
    > The solution is to convert your float value, input, into an integer number
    > of pennies (I thought you Americans used cents, but that's by the by).


    <OT>
    A "cent" is a unit of currency equal to $0.01 (one hundredth of a
    dollar). A "penny" is an informal name for the one-cent coin; the
    term is also sometimes used as a synonym for "cent". Similarly,
    "nickel" is the informal name for a five-cent coin. A "dime" is
    actually a unit of currency equal to $0.10, or 10 cents, but these
    days the term is used almost exclusively to refer to the 10-cent coin.
    </OT>

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Jul 15, 2004
    #5
  6. Shawn

    Richard Bos Guest

    Eric Sosman <> wrote:

    > Hint: What should your program do if someone asks for $0.14159
    > in change?


    Sell him some more pie?

    Richard
    Richard Bos, Jul 15, 2004
    #6
  7. Keith Thompson <> scribbled the following:
    > "Malcolm" <> writes:
    > [...]
    >> The solution is to convert your float value, input, into an integer number
    >> of pennies (I thought you Americans used cents, but that's by the by).


    > <OT>
    > A "cent" is a unit of currency equal to $0.01 (one hundredth of a
    > dollar). A "penny" is an informal name for the one-cent coin; the
    > term is also sometimes used as a synonym for "cent". Similarly,
    > "nickel" is the informal name for a five-cent coin. A "dime" is
    > actually a unit of currency equal to $0.10, or 10 cents, but these
    > days the term is used almost exclusively to refer to the 10-cent coin.
    > </OT>


    Similarly, I've heard that the British use "pence" to refer a monetary
    sum, but "pennies" to refer to a collection of coins.

    --
    /-- Joona Palaste () ------------- Finland --------\
    \-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
    "We're women. We've got double standards to live up to."
    - Ally McBeal
    Joona I Palaste, Jul 15, 2004
    #7
  8. Shawn

    Alex Fraser Guest

    [OT] Re: Beginner question: Precision of floating point arithmetic...

    "Joona I Palaste" <> wrote in message
    news:cd5q6i$ajp$...
    [snip]
    > Similarly, I've heard that the British use "pence" to refer a monetary
    > sum, but "pennies" to refer to a collection of coins.


    Yes. The coins are labeled "ONE PENNY". Paradoxically, older ones say "NEW
    PENNY" :).

    Alex
    Alex Fraser, Jul 15, 2004
    #8
  9. Shawn

    Lew Pitcher Guest

    Re: [OT] Re: Beginner question: Precision of floating point arithmetic...

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Alex Fraser wrote:
    > "Joona I Palaste" <> wrote in message
    > news:cd5q6i$ajp$...
    > [snip]
    >
    >>Similarly, I've heard that the British use "pence" to refer a monetary
    >>sum, but "pennies" to refer to a collection of coins.

    >
    >
    > Yes. The coins are labeled "ONE PENNY". Paradoxically, older ones say "NEW
    > PENNY" :).


    And, what are the ones issued before 1971 called?


    (hint: http://en.wikipedia.org/wiki/Pound_Sterling)

    - --
    Lew Pitcher
    IT Consultant, Enterprise Application Architecture,
    Enterprise Technology Solutions, TD Bank Financial Group

    (Opinions expressed are my own, not my employers')
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.4 (MingW32)

    iD8DBQFA9tR1agVFX4UWr64RAs3gAJ40ryG1l3Owc1B2H73/D8HMuybuBwCg8qsZ
    gsF5XJD9iUppsot0mwyD6GI=
    =W7md
    -----END PGP SIGNATURE-----
    Lew Pitcher, Jul 15, 2004
    #9
  10. Shawn

    Alex Fraser Guest

    Re: [OT] Re: Beginner question: Precision of floating point arithmetic...

    "Lew Pitcher" <> wrote in message
    news:8uAJc.26706$...
    > -----BEGIN PGP SIGNED MESSAGE-----
    > Hash: SHA1
    >
    > Alex Fraser wrote:
    > > "Joona I Palaste" <> wrote in message
    > > news:cd5q6i$ajp$...
    > > [snip]
    > >
    > >>Similarly, I've heard that the British use "pence" to refer a monetary
    > >>sum, but "pennies" to refer to a collection of coins.

    > >
    > >
    > > Yes. The coins are labeled "ONE PENNY". Paradoxically, older ones say
    > > "NEW PENNY" :).

    >
    > And, what are the ones issued before 1971 called?


    Annoyingly large?

    Alex
    Alex Fraser, Jul 15, 2004
    #10
  11. Re: [OT] Re: Beginner question: Precision of floating point arithmetic...

    On Thu, 15 Jul 2004 15:01:12 -0400, in comp.lang.c , Lew Pitcher
    <> wrote:

    >Alex Fraser wrote:
    >>
    >> Yes. The coins are labeled "ONE PENNY". Paradoxically, older ones say "NEW
    >> PENNY" :).

    >
    >And, what are the ones issued before 1971 called?


    One penny. symbol d.

    Bonus points for remembering the value of a farthing, groat, tanner, half
    dollar and pound scots. Without looking on wikipedia or google.

    --
    Mark McIntyre
    CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
    CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>


    ----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
    http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
    ---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
    Mark McIntyre, Jul 15, 2004
    #11
  12. Joona I Palaste <> wrote in message news:<cd5q6i$ajp$>...
    > Keith Thompson <> scribbled the following:
    > > "Malcolm" <> writes:
    > > [...]
    > >> The solution is to convert your float value, input, into an integer number
    > >> of pennies (I thought you Americans used cents, but that's by the by).

    >
    > > <OT>
    > > A "cent" is a unit of currency equal to $0.01 (one hundredth of a
    > > dollar). A "penny" is an informal name for the one-cent coin; the
    > > term is also sometimes used as a synonym for "cent". Similarly,
    > > "nickel" is the informal name for a five-cent coin. A "dime" is
    > > actually a unit of currency equal to $0.10, or 10 cents, but these
    > > days the term is used almost exclusively to refer to the 10-cent coin.
    > > </OT>

    >
    > Similarly, I've heard that the British use "pence" to refer a monetary
    > sum, but "pennies" to refer to a collection of coins.


    <OT>
    A US penny is 1/100 of a dollar; a British penny (since 1971) is 1/100
    of a pound. I figured the Brits used "pence" as the more traditional
    plural, (e.g. there is an American music group with the name Sixpence
    None The Richer), Americans use "pennies" or "cents" (as a penny is a
    centidollar).

    The U.S. mint produces six different general currency coin
    denominations: penny ($.01), nickel ($.05) (so named because early
    versions were made of nickel or a nickel alloy), dime ($.10) (the name
    is from the French disme), quarter ($.25), half dollar ($.50), and
    dollar coins ($1.00). The Mint also produces coins for numismatic
    appeal, such as $20 gold coins, that are not generally used as
    currency.
    </OT>

    Gregory Pietsch
    Gregory Pietsch, Jul 21, 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. Roger Leigh
    Replies:
    4
    Views:
    459
    Roger Leigh
    Nov 12, 2003
  2. BigMan
    Replies:
    16
    Views:
    591
    E. Robert Tisdale
    Apr 13, 2005
  3. Joon Kim

    question : floating point precision.

    Joon Kim, Jun 4, 2009, in forum: C Programming
    Replies:
    41
    Views:
    1,339
    jacob navia
    Jun 22, 2009
  4. jfcg
    Replies:
    0
    Views:
    270
  5. Saraswati lakki
    Replies:
    0
    Views:
    1,287
    Saraswati lakki
    Jan 6, 2012
Loading...

Share This Page