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.