title: A realistic example where using BigDecimal for currency is strictly better than using double
body: <p>We <a href="https://stackoverflow.com/q/3730019/581205">know</a> that using <code>double</code> for currency is error-prone and not recommended. However, I'm yet to see a <strong>realistic</strong> example, where <code>BigDecimal</code> works while <code>double</code> fails and can't be simply fixed by some rounding.</p>
  
  <hr>
  
  <p>Note that trivial problems </p>
  
  <pre><code>double total = 0.0;
  for (int i = 0; i &lt; 10; i++) total += 0.1;
  for (int i = 0; i &lt; 10; i++) total -= 0.1;
  assertTrue(total == 0.0);
  </code></pre>
  
  <p>don't count as they're trivially solved by rounding (in this example anything from zero to sixteen decimal places would do).</p>
  
  <hr>
  
  <p>Computations involving summing big values may need some intermediate rouding, but given the <a href="https://en.wikipedia.org/wiki/Circulation_(currency)#Total_currency_in_circulation" rel="noreferrer">total currency in circulation</a> being <code>USD 1e12</code>, Java <code>double</code> (i.e., the standard <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format" rel="noreferrer">IEEE double precision</a>) with its 15 decimal digits is still sufficient event for cents.</p>
  
  <hr>
  
  <p>Computations involving division are in general imprecise even with <code>BigDecimal</code>. I can construct a computation which can't be performed with <code>double</code>s, but can be performed with <code>BigDecimal</code> using a scale of 100, but it's not something you can encounter in reality.</p>
  
  <hr>
  
  <p><em>I don't claim that such a</em> realistic <em>example does not exist, it's just that I haven't seen it yet.</em></p>
  
  <p>I also surely agree, that using <code>double</code> is more error-prone.</p>
  
  <h3>Example</h3>
  
  <p>What I'm looking for is a method like the following (based on the answer by Roland Illig)</p>
  
  <pre><code>/** 
    * Given an input which has three decimal places,
    * round it to two decimal places using HALF_EVEN.
  */
  BigDecimal roundToTwoPlaces(BigDecimal n) {
      // To make sure, that the input has three decimal places.
      checkArgument(n.scale() == 3);
      return n.round(new MathContext(2, RoundingMode.HALF_EVEN));
  }
  </code></pre>
  
  <p>together with a test like</p>
  
  <pre><code>public void testRoundToTwoPlaces() {
      final BigDecimal n = new BigDecimal("0.615");
      final BigDecimal expected = new BigDecimal("0.62");
      final BigDecimal actual = roundToTwoPlaces(n);
      Assert.assertEquals(expected, actual);
  }
  </code></pre>
  
  <p>When this gets naively rewritten using <code>double</code>, then the test could fail (it doesn't for the given input, but it does for others). However, it can be done correctly:</p>
  
  <pre><code>static double roundToTwoPlaces(double n) {
      final long m = Math.round(1000.0 * n);
      final double x = 0.1 * m;
      final long r = (long) Math.rint(x);
      return r / 100.0;
  }
  </code></pre>
  
  <p>It's ugly and error-prone (and can probably be simplified), but it can be easily encapsulated somewhere. That's why I'm looking for more answers.</p>