-1

First, my environment:

Distributor ID: Bunsenlabs Description: BunsenLabs GNU/Linux 10.5 (Lithium) Release: 10.5 Codename: buster

Thread model: posix gcc version 8.3.0 (Debian 8.3.0-6)

I working on an old C program and ran into a rounding error in the program. I have copied the code into an the program "example.c" below:

main()
{
    float acntBalance;
    int dollars;
    int cents;
    float fcents;
    
    dollars = 303466;
    cents = 95; 
    fcents = cents * 0.01;
    acntBalance = dollars + fcents;
    printf("Dollars(%d) + Cents(%f) = %f \n",dollars,fcents,acntBalance);
}

and compiled this code using the GNU compiler as follows:

gcc -w -g -o example example.c

Adding 303466 dollars to 95 cents should be 303466.95, but prints out as 303466.937500.

This is an accounting program and being 1 cent off is not acceptable.

This looks like a bug to me, but it has been so long since I worked on a C program, so I will say "user error" is the mostly like problem here. But this seems so basic, that I don't see where I am making an error.

If the error is not mine, is it H/W or S/W. I have run the program on 2 different hosts, so it leads me to believe it is a S/W error. But where?

Can anyone see an error in my code?

Jim
  • 27
  • 5
  • 1
    Very likely it is the result of how floating point numbers work. The `float` type will only give you about [7 digits of precision](https://en.wikipedia.org/wiki/Single-precision_floating-point_format). – Robert Harvey Jan 05 '23 at 22:39
  • 1
    [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) is worth a read. You should *never* use floating point values for currency calculations. [Why not use Double or Float to represent currency?](https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency) – Retired Ninja Jan 05 '23 at 22:40
  • 3
    How do you fix it? Store everything as cents in integer types, do integer arithmetic, and then format the result properly as dollars and cents when you display it. – Robert Harvey Jan 05 '23 at 22:40
  • This will never work using type `float`. At the very least, (a) use type `double` for your `acntBalance`. Then, (b) print it using `%.2f` at the end. – Steve Summit Jan 05 '23 at 22:50
  • The number 303466.95 does not exist in single-precision floating point. The closest you can get is 303466.93 or 303466.94 (really 303466.9375, as you saw). That number does not exist in double precision, either, but there, at least, you can get a number like 303466.95000000001, which is close enough, as long as you use `%.2f` when printing to round off the unwanted 0.00000000001. – Steve Summit Jan 05 '23 at 22:54
  • Thank you for the responses. I used Robert Harvey's suggestion. I wanted to follow up to add to his explanation to clarify that my problem was indeed a "user error", but at least for me the reason was a bit subtle. My error was that I was looking at rounding of cents from 0.95 to 0.937500 as a rounding error at 2 digits. Wrong! When the expression is evaluated, the total value 303466 dollars gets cast to a float of 303466.xxxx to which the floating point value of 0.xxxx gets added. Obviously, the rounding is done to an 8 digit floating point value, not just the cents. My error!!! – Jim Jan 06 '23 at 15:01

1 Answers1

0

%.1f = one decimal place %.2f = two decimal places ...

printf("Dollars(%d) + Cents(%f) = %.2f \n",dollars,fcents,acntBalance);

  • That would print 94 cents in this case, not 95. The real problem is that `float` is inexact, but OP wants exact amounts. – alter_igel Jan 05 '23 at 23:33