Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy is using a NON-decimal data type bad for money?
    text
    copied!<p><strong>tl;dr:</strong> What's wrong with my <code>Cur</code> (currency) structure?</p> <p><strong>tl;dr 2:</strong> <em>Read the rest of the question please, before giving an example with <code>float</code> or <code>double</code>.</em> :-)</p> <hr> <p>I'm aware that this question has come up numerous times before all around the internet, but <em>I have not yet seen a convincing answer</em>, so I thought I'd ask again.</p> <p>I fail to understand why using a non-decimal data type is bad for handling money. (That refers to data types that store binary digits instead of decimal digits.)</p> <p>True, it's not wise to compare two <code>double</code>s with <code>a == b</code>. But you can easily say <code>a - b &lt;= EPSILON</code> or something like that.</p> <p><em>What is wrong with this approach?</em></p> <p>For instance, I just made a <code>struct</code> in C# that I believe handles money correctly, without using any decimal-based data formats:</p> <pre><code>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 &lt;(Cur a, Cur b) { return (a.val - b.val) &lt; -EPS; } static bool operator &gt;(Cur a, Cur b) { return (a.val - b.val) &gt; +EPS; } static bool operator &lt;=(Cur a, Cur b) { return (a.val - b.val) &lt;= +EPS; } static bool operator &gt;=(Cur a, Cur b) { return (a.val - b.val) &gt;= -EPS; } static bool operator !=(Cur a, Cur b) { return Math.Abs(a.val - b.val) &lt; EPS; } static bool operator ==(Cur a, Cur b) { return Math.Abs(a.val - b.val) &gt; EPS; } bool Equals(Cur other) { return this == other; } override int GetHashCode() { return ((double)this).GetHashCode(); } override bool Equals(object o) { return o is Cur &amp;&amp; this.Equals((Cur)o); } override string ToString() { return this.val.ToString("C4"); } } </code></pre> <p>(Sorry for changing the name <code>Currency</code> to <code>Cur</code>, for the poor variable names, for omitting the <code>public</code>, and for the bad layout; I tried to fit it all onto the screen so that you could read it without scrolling.) :)</p> <p>You can use it like:</p> <pre><code>Currency a = 2.50; Console.WriteLine(a * 2); </code></pre> <p>Of course, C# has the <code>decimal</code> data type, but that's beside the point here -- the question is about why the above is dangerous, not why we shouldn't use <code>decimal</code>.</p> <p>So would someone mind providing me with <em>a real-world counterexample</em> of a dangerous statement that would fail for this in C#? I can't think of any.</p> <p>Thanks!</p> <hr> <p>Note: I am <strong><em>not</em></strong> debating whether <code>decimal</code> is a good choice. I'm asking why a binary-based system is said to be inappropriate.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload