tl; dr: What happened to my Cur (currency) structure?
tl; dr 2: Read the rest of the question before giving an example with float or double . double
I know that this question has arisen many times earlier than anything else on the Internet, but I have not yet seen a convincing answer, so I thought I would ask again.
I do not understand why using a non-decimal data type is bad for processing money. (This applies to data types that store binary digits instead of decimal digits.)
True, it is impractical to compare two double with a == b . But you can easily say a - b <= EPSILON or something like that.
What is wrong with this approach?
For example, I just did a struct in C #, which I believe handles money correctly without using any data formats based on decimals:
struct Cur { private const double EPS = 0.00005; private double val; Cur(double val) { this.val = Math.Round(val, 4); } static Cur operator +(Cur a, Cur b) { return new Cur(a.val + b.val); } static Cur operator -(Cur a, Cur b) { return new Cur(a.val - b.val); } static Cur operator *(Cur a, double factor) { return new Cur(a.val * factor); } static Cur operator *(double factor, Cur a) { return new Cur(a.val * factor); } static Cur operator /(Cur a, double factor) { return new Cur(a.val / factor); } static explicit operator double(Cur c) { return Math.Round(c.val, 4); } static implicit operator Cur(double d) { return new Cur(d); } static bool operator <(Cur a, Cur b) { return (a.val - b.val) < -EPS; } static bool operator >(Cur a, Cur b) { return (a.val - b.val) > +EPS; } static bool operator <=(Cur a, Cur b) { return (a.val - b.val) <= +EPS; } static bool operator >=(Cur a, Cur b) { return (a.val - b.val) >= -EPS; } static bool operator !=(Cur a, Cur b) { return Math.Abs(a.val - b.val) < EPS; } static bool operator ==(Cur a, Cur b) { return Math.Abs(a.val - b.val) > EPS; } bool Equals(Cur other) { return this == other; } override int GetHashCode() { return ((double)this).GetHashCode(); } override bool Equals(object o) { return o is Cur && this.Equals((Cur)o); } override string ToString() { return this.val.ToString("C4"); } }
(Sorry for changing the Currency name to Cur , for poor variable names, for public exceptions, and for poor layout, I tried putting all of this on the screen so you can read it without scrolling.) :)
You can use it like:
Currency a = 2.50; Console.WriteLine(a * 2);
Of course, C # has a decimal data type, but that’s the point here - the question is why it is dangerous and not why we should not use decimal .
So could someone give me a real counterexample from a dangerous statement that would not work for this in C #? I can’t come up with.
Thanks!
Note. I am not discussing whether decimal good choice. I ask why a binary system is considered inappropriate.