1

This is my first time posting here so this post might be a little bit of a mess but I'll try my best to explain everything.

I have to make a program that acts kinda like Self-checkout in a store. However i run into two issues when people are inserting money into the machine. People insert money like this: 10 20 50 0.10 .... and the paying ends with 0 or by using ctrl+d. (people can only use coins of this value: 100, 50, 20, 10, 5, 2, 1, 0.50, 0.20, 0.10, 0.05, 0.02 a 0.01 as you can see in the code)

Well when I end the payment with 0 program exits normally.(like this: 50 20 0)

However when I end it with ctrl+d it causes infinite loop and i don't understand why.

And the second issue is that for some reason it won't add numbers like 0.10, 0.20 and so on. Any ideas how to fix this or what might be causing the error?

And dont mind the printf in the middle that was just me checking the value.

float bill,x,payment=0,k=0;



printf("coins ");
while(k==0)
{
    scanf("%f", &x);
    if(x==0 )
    {
        goto END;
    }

    if(x ==100 || x ==50 || x ==20 || x ==10 || x ==5 || x ==2 || x ==1 || x ==0.50 || x==0.10 || x ==0.20 || x ==0.05 || x ==0.02|| x ==0.01 )
        {   
            payment += x;
            printf("==============");
            printf("%.2f  \n",payment);
        }

    else{
        printf("%.2f is invalid",x);
        k = 1;      
        goto END2;
    }
}
END:
printf("%.2f  \n", payment);

END2:
return 0;
Thomas
  • 13
  • 3
  • 3
    You should check the return value of scanf, expecially if you want to "end it with ctrl+d". – Bob__ Nov 24 '18 at 22:17
  • I wanted to point out the same as @Bob__ did http://www.cplusplus.com/reference/cstdio/scanf/ the scanf function can fail and you do not consider it. – petrch Nov 24 '18 at 22:18
  • 2
    You would be better off keeping the money in pennies rather than using floating point for fractions. – Retired Ninja Nov 24 '18 at 22:38
  • Yeah, It could be said, that *never* use floating point numbers for money (unless you intentionally want rounding errors to add up to visible amounts...). – hyde Nov 24 '18 at 22:40
  • @hyde: First, there are decimal floating-point formats in both hardware (including Intel and IBM) and software (including Microsoft) that are perfectly fine for doing the kind of currency calculations shown in this question. So the advice never to use floating-point for money is wrong on that count. Second, floating-point formats, whether binary or decimal, are appropriate for working on financial calculations such as stock market option evaluation, properly designed mortgage calculations, or even calculating sales taxes when done correctly. – Eric Postpischil Nov 25 '18 at 00:30
  • @EricPostpischil Sure, let me clarify: never use binary floating point types of C for money, unless you can show it will not be a problem, and don't bother even thinking about that unless you can also show the benefit of using floats. – hyde Nov 25 '18 at 00:49
  • Floating point, see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/. – Neil Nov 25 '18 at 03:37

3 Answers3

2

When you send Ctrl+D in your terminal, you register an EOF character to stdin, therefore scanf won't read anything anymore, and x will never be set to 0, so you won't escape your loop.

You would need to check the result of scanf, reading man scanf you can see that you are expecting a return value > 0 in case of success.

if (scanf("%f", &x) < 1 || x = 0) // Check return value of scanf, then check x
    GOTO: END;

Edit: Note that if scanf was reading input items, you would need to check that the return value of scanf is not less that the number of input items.

alamit
  • 392
  • 2
  • 10
  • This will also work if you have a read error; you could really get fancy by checking if `errno` is set on `END` and `perror`. – Neil Nov 24 '18 at 22:32
1

Fixing this answer based on hyde's and alamit's comments

The reason your program "refuses" to add small numbers like 0.10 is because your variable x and the decimal literals like 0.10 you are comparing it to have different precision.

So, to fix the problem, add f to the values x == 0.10f, or switch to using double and reading and printing with %lf

If you want to know the math behind the problem, read this.

Lev M.
  • 6,088
  • 1
  • 10
  • 23
  • 1
    It's not about precision of *float*. 0.1 can't be accurately represented with binary "decimal", same way 1/3 can not be represented with base 10 decimals (it becomes 0.33...). Using *double* will only seem to help, but doesn't for real. – hyde Nov 24 '18 at 22:39
  • @hyde So why does it work with double? I know ranged comparison < > is recommended for floating point, but it seems like an overkill for this exercise. I compiled and ran the code with double and it passes the if condition. Do you know why? – Lev M. Nov 24 '18 at 22:46
  • 1
    The issue comes from comparing `float` with `double`, which doesn't have the same precision, and therefore won't store the same result for a repeating binary number such as 0.1. To compare with a float literal OP should use `0.1f` for example. – alamit Nov 24 '18 at 22:49
  • @alamit thanks, I forgot C defaults to double for decimal literals. – Lev M. Nov 24 '18 at 22:54
  • If you have matching types (either both float or both double), then 0.1 parsed as that will equal 0.1 parsed as that. But it won't be equal to 0.1 decimal, ever (because neither *float* or *double* has a bit pattern which would be 0.1 decimal). You can change the equality comparison to use *float* by comparing to `1.0f`, if you don't want to change the variable type to *double*, and it would "work" again (for suitably defined values of "work"). – hyde Nov 24 '18 at 22:56
  • Thank you. Your and @Talip Tolga Sarı 's answers helped me as well. I wish i could tick more than one reply. – Thomas Nov 25 '18 at 00:26
1

When making comparisons with floating point numbers, one must be careful. Floating point representation of 0.1 is different between 32 bits and 64 bits(float vs double). You have defined x to be float which is compared with 0.1(which is double). So the comparison will not work correctly. Either you must define x as double and change nothing else in your code or, make x == 0.1 to x == 0.1f

Further information about this topic can be found this answer and this topic