1

I have been making a little hobby program that calculates how much change should be given for a certain amount. Example:

IN: ./program £5.50
OUT: £5 x 1
OUT: £0.50 x 1

But when it comes to dealing with certain numbers that end in 0.01 or 0.05, the code 'jumps' them or giving weird results, for example instead of giving £0.05 x 1 it gives £0.02 x 2 and then skips £0.01.

Here's the code:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define NUMB_OF_CHANGE_AVAILABLE 12

float diff_change[NUMB_OF_CHANGE_AVAILABLE] = {
    50, 20, 10, 5,
    2, 1, 0.5, 0.2,
    0.1, 0.05, 0.02, 0.01} ;

void calc_change_needed(float total_amount) ;

int main(int argc, char const *argv[]) {
    float total_amount ;

    if (argv[1] == NULL)
    {
        printf("Please put number as first argument. Example:\n") ;
        printf("> ./program 5.55\n") ;
        return 0 ;
    } ;

    sscanf(argv[1], "%f", &total_amount) ;
    printf("Change number given: £%.2f\n", total_amount) ;
    calc_change_needed(total_amount) ;

    return 0;
} ;

void calc_change_needed(float total_amount)
{
    int i, multiples_needed ;
    float buffer_amount ;
    float amount_left = total_amount ;

    for (i = 0 ; i < NUMB_OF_CHANGE_AVAILABLE ; ++i)
    {
        multiples_needed = amount_left / diff_change[i] ;
        if (multiples_needed == 0) continue ;
        amount_left = amount_left - (multiples_needed * diff_change[i]) ;

        printf("£%.2f x %d\n", diff_change[i], multiples_needed) ;
    } ;

    if (amount_left == 0.01) printf("£0.01 x 1\n") ;
} ;

Even though I wrote that an output of 0.01 should be given (I expected the last one to be skipped), it still won't output it, even if amount_left is 0.01.

Some examples I've gone through that do not give right output:

IN: ./program 0.35
OUT: Change number given: £0.35
OUT: £0.20 x 1
OUT: £0.10 x 1
OUT: £0.02 x 2
IN: ./program 5.85
OUT: Change number given: £5.85
OUT: £5.00 x 1
OUT: £0.50 x 1
OUT: £0.20 x 1
OUT: £0.10 x 1
OUT: £0.02 x 2

Although it does work with some numbers ending in 0.01 or 0.05, example:

IN: ./program 8.01
OUT: Change number given: £8.01
OUT: £5.00 x 1
OUT: £2.00 x 1
OUT: £1.00 x 1
OUT: £0.01 x 1
IN: ./program 8.06
OUT: Change number given: £8.06
OUT: £5.00 x 1
OUT: £2.00 x 1
OUT: £1.00 x 1
OUT: £0.05 x 1
OUT: £0.01 x 1

Edit: thanks for all the comments, I realised what the problem was. I’m just gonna change to just deal with int now instead of float. I guess I was too fixed with fixing the problem of the calculation instead of trying to think if, perhaps, it was the idea itself (of working with decimals) that was wrong to behind with. Will always keep this in mind for future projects :) (Although I have no idea why this post was downvoted lol)

Leonardo
  • 23
  • 5

1 Answers1

1

The overall primary problem is that float is certainly a base-2 floating point encoding like binary32. This money problem needs exact math for values for decimal fractions like 0.01, 0.05 and those values are not exactly representable in float. Never use float with money.

Investigation is further made difficult with amount_left == 0.01, which compares equality of a float to a double - nearly always this is false given the mis-matched precisions.

Instead, take input and constants into integer ones of the smallest money unit, perform internal math as integers, and print out as needed.

#include <math.h>

...
double total_amount;
sscanf(argv[1], "%lf", &total_amount) ;
long long i_total_amount = llround(total_amount * 100.0);
  ...
  long i_change = lround(diff_change[i] * 100.0);
  // perform integer math with i_total_amount, i_change
  ...
printf("£%.2f\n", i_total_amount/100.0);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256