2

The following code converts dollars (floating values) into cents (integer values). Here 1 dollar == 100 cents. The code works flawlessly except for one value i.e 4.2. It gives output as 419 instead of 420 for 4.2 as input. Where is the bug?

#include <stdio.h>
int main(void)
{   
    float change;

    do
    {
        printf("O hai! Enter amount in dollars to convert in cents.\n");

        scanf("%f",&change);   //accepts input in dollars

    } while(change < 0.00);

    int i = change * 100;    //converts dollars into cents

    printf("The equivalent cents are %d\n",i);
}
  • 3
    Time to read the [floating point guide](http://floating-point-gui.de). – pmg Jun 04 '17 at 12:48
  • 1
    And [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) It is best to use `int` types for "change" problems and work in cents. – Weather Vane Jun 04 '17 at 12:53
  • 2
    Always prefer `double` when dealing with floating point values. – pmg Jun 04 '17 at 12:55
  • 3
    have you checked all possible float values and make sure that this is the only one that's not working? – phuclv Jun 04 '17 at 13:11
  • 1
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – phuclv Jun 04 '17 at 13:11
  • Not all possible float values but I tried several similar combinations like 3.1, 5.1, 4.15 and so on for which that code worked. – Nikhil Lakare Jun 04 '17 at 13:20

4 Answers4

3

You have this behavior because of the way a float is represented.

In IEEE 754, 4.2 is actually stored as 4.19999980926513671875 so that when you multiply it by 100 and cast it back to an int, you get 419 (i.e. the integer part of the result).

A solution would be to use

int i = (int) roundf(change * 100);

or

int i = (int) lrintf(change * 100);

with #include <math.h>.

PiCTo
  • 924
  • 1
  • 11
  • 23
2

Many floating point values do not have an exact representation in base 2.

You can try adding a very small value to push the value a little bit:

int i = (change + 0.0001) * 100;    //converts dollars into cents
pmg
  • 106,608
  • 13
  • 126
  • 198
2

As you can see here when you store a value in a float the actual number stored is not always what you expected. This is due to how floats are represented in binary (you can learn more on wiki).

Now, as shown in the 1st link, when you try to store 4.2 in change, you actually store 4.19.... Multiply it by 100, store it inside an int,and you get 419.

Changing your float into double will give you better (double) precision, and in your case, it will yield the expected result

double change; # float changed to double
do
{
    printf("O hai! Enter amount in dollars to convert in cents.\n");

    scanf("%lf",&change);   //accepts input in dollars # "%f" changed to "%lf"

} while(change < 0.00);

int i = change * 100;    //converts dollars into cents

printf("The equivalent cents are %d\n",i);

input: 4.2
output: 420

on my machine.

Note that using double is not a fail-safe. It can also give misleading results, but it should behave better than float.

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • The extra precision of `double` vs `float` does not help, in general. Converting `x.9999999` or `x.99999999999999999` to an `int` is just as problematic. – chux - Reinstate Monica Jun 04 '17 at 14:48
  • As I mentioned, double is a better, not overall good. For this post, is makes the difference :) – CIsForCookies Jun 04 '17 at 14:52
  • 1
    For the value of 4.2 using `double` may make a difference, but it does not decrease the chance of the problem versus using `float`. About half of all "decimal" values like 4.2, 1.23, 123.456, ... have this problem using `float` _or_ `double`. – chux - Reinstate Monica Jun 04 '17 at 15:03
0

In this case that you know that the decimals for work with money are 2, I suggest that work with float representation with 3 decimals, and then the result must do round up to 2 decimals. Is important be carefully, because the working with money is very delicate. Hope this help.

Luis Carlos
  • 345
  • 3
  • 10