26

When testing greedy.c, all numbers appeared to work except 4.2 (annoying since 4.2 is in the check50 test). I get 22 coins instead of 18.

I printed my variables at each stage of the problem and found that, when I times 4.2 by one hundred, to get 420, I instead get 419. My code works by taking away the largest possible coin value from 420, until I reach zero, adding 1 to 'counter' each time. I found that, if I use 420 as the starting value, the last value is ten, at which point I can take away 10 cents, giving me a final answer of 18 coins. Because my program starts at 419, I instead reach a value of 9, at which point the program takes a 5, then 1 multiple times, giving me a final answer of 22 coins.

I have already looked at Why does an input of 4.2 yield an output of 22 not 18? but it did not help. I have also tried changing the variable from a float to a double but this did not work either.

The code that gives me 419 when I input 4.2 is below:

//Get change from user
do
{
    printf("O hai! How much change (in $) is owed?\n");
    change = GetFloat();
    change = roundf(change*100)/100; //rounds numbers to 2 d.p
}while (change<0);

//Put into cents
c = change*100;
43

First of all, kudos for debugging your program and identifying the problem as having to do with multiplying your input. Let's take a look at that part of your code step by step, to illustrate what's going wrong.

change = GetFloat();

At this point, we're going to enter 4.2; let's make sure we see very precisely what number gets stored by printing out the value with lots of significant digits:

printf("%.20f", change);

The result is 4.19999980926513671875, which is normal for floating point values. We talked about floating point accuracy in this older question: Why don't I get the correct result when dividing numbers for greedy?

Now you have the line:

change = roundf(change*100)/100;

The first thing that happens here is change*100 is calculated inside the parentheses. That gives us 419.99996948242187500000 -- again, slightly different than what you might expect after the last value we saw, but still close enough to 420 for our purposes.

Now, after the first arithmetic step, we can imagine that our line might look something like this:

change = roundf(419.999969482421875)/100;

The remaining steps are the roundf() call and the division arithmetic; the function call happens first. This time, we get exactly what we expect, i.e., 420.00000000000000000000. But notice that the return value of roundf() is still a floating-point type, even though we rounded it to the nearest whole value! Now we have:

change = 420.00000000000000000000/100;

The last step is the division arithmetic. Now, what do you expect? Looking back at the last few times we performed arithmetic on a float, you might have already figured out what's coming: the result is 4.19999980926513671875, just what we started with!

Now, when it comes time to "Put into cents," you're doing the first step again and trying to store 419.999969482421875 in an int type, which is why you get 419 instead of 420.

So, what was the closest that we got to our desired result? Well, 420.00000000000000000000 isn't bad; it looks like the number we want, just with a little extra precision. All we need to do is make it an actual integer, instead of a whole number stored as a float. Instead of performing the division arithmetic, we can cast the floating-point value to an int type and get the number we want.

There are two ways to do it. Here's the implicit way:

int c;
float change = 4.2;
c = roundf(change*100);  // value on right side of '=' is 420.0; value stored is 420

It's "implicit" because we don't actually tell the number it should turn into an int value; we just shove it into c, which we previously declared can only hold that type of data. Here's the explicit way:

int c;
float change = 4.2;
c = (int) roundf(change*100);  // value on the right side of '=' is now 420

It's "explicit" because we used the cast operator, which is a type name in parentheses before the value that we want to cast to some specific type. By putting (int) in front of roundf(), we're clearly saying that whatever return value comes out of roundf() is going to be cast to an integer.

One other thing I would change about your code is to move the calculations out of the do-while loop. That loop only cares whether the input is positive and non-zero; why waste time doing calculations before you know you have good input? All you really need in that loop are the first two lines. Then you can do your arithmetic and rounding in one step, using either the implicit or explicit method above to cast the result to an integer value.

3
  • 2
    I know I should avoid comments which say thanks, but thank you so much that was driving me insane! Aug 12 '14 at 16:50
  • @ShirazButt Conversation is fine in comments, we just like to keep them out of the questions and answers themselves. Glad to have helped you solve this problem.
    – Air
    Aug 12 '14 at 18:50
  • thanks indeed for this, spent 2 hours looking for this!
    – Salva Tore
    Mar 18 '16 at 14:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .