Is using floating point type for money/currency a good idea?

ag0aep6g anonymous at example.com
Mon May 20 12:43:20 UTC 2019


On 20.05.19 13:47, Josh wrote:
> Normally I would say no, no and no.  Rounding issues will kill you every 
> time.

And you'd be right.

>  However:
> 
> import std.stdio;
> import std.range;
> 
> void main()
> {
>      foreach (i; iota(1, 1000)) {
>          writefln("%f", cast(float) i / 100.0);
>      }
> }
> 
> Doesn't show any rounding issues, but you still might hit them at large 
> values...I just remember back in the day having numbers like 
> 0.199999999999999, but maybe that problem has been solved.

That "problem" hasn't been solved. It can't be solved. `1 / 100.0` might 
print as 0.01, but it isn't exactly 0.01. The output is just rounded. If 
you add more decimals (e.g. `writefln("%.20f", ...)`), those niners will 
show up.

Aside from large and small values, you'll also see significant 
(accumulated) rounding error when doing many operations on your numbers. 
For example, if you add 0.1 ten thousand times, you might expect the 
result to be 1000, but with `float` it's not that:

import std.stdio;
void main()
{
     float x = 0;
     foreach (i; 0 .. 10_000) x += 0.1;
     writeln(x); /* Prints "999.903". */
}

> What would be safer is to do "fixed point" math, i.e. use an integer and 
> when displaying the value convert it to float and divide by 100.  So if 
> the user has 50 cents they internal value would be 50, if you give them 
> a dollar twenty five (125) then they would have 175, and when you go to 
> display it, dividing by 100 will display 1.75.

Yup.

> As long as you are not multiplying money by money you will be fine.  50 
> cents times 5 is 2.50 (50 * 5 = 250), however 50 cents times 50 cents is 
> 2500, which makes no sense but so does multiplying money by money...

50 cents times 50 cents is 2500 square cents. Makes perfect sense.


More information about the Digitalmars-d-learn mailing list