Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8297308

BigDecimal rounding with MathContext does not work as expected during multiplication/division

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Windows 10

      A DESCRIPTION OF THE PROBLEM :
      BigDecimal rounding does not work as expected during multiplication/division, when provided with MathContext having the precision details.

      After multiplication/division, if we set the scale like below, it works as expected
                  .setScale(8, BigDecimal.ROUND_HALF_UP)

      But if we provide the equivalent scale using MathContext, like below, it does not round it properly, but instead truncates it by 2 decimal places..!
              new MathContext(8, RoundingMode.HALF_UP)

      Also, during division, if we directly divide a BigDecimal with another without specifying precision details, we get an exception. (This works with multiplication though)
             BigDecimal quantity = new BigDecimal(178643);
             val1 = quantity.divide(new BigDecimal(1.0394)); // Exception at this point - "java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result."
            "java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result."

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      // Multiplication -- using setScale
              BigDecimal quantity = new BigDecimal(178643);
              BigDecimal val1 = quantity.multiply(new BigDecimal(1.0394)).setScale(8, BigDecimal.ROUND_HALF_UP);
              // Multiplication -- precision by using MathContext.
              BigDecimal val2 = quantity.multiply(new BigDecimal(1.0394), new MathContext(8, RoundingMode.HALF_UP));
              System.out.println("After multiplication, with normal rounding, val1 =" + val1
                      + ", rounding using math context, val2=" + val2);
              // Division -- using setScale -- This produces an error:
                  // "java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result."
              // val1 = quantity.divide(new BigDecimal(1.0394)).setScale(8, BigDecimal.ROUND_HALF_UP);
              // Division -- passing the scale and rounding mode - works fine.
              val1 = quantity.divide(new BigDecimal(1.0394), 8, RoundingMode.HALF_UP);
              // Division -- precision by using MathContext.
              val2 = quantity.divide(new BigDecimal(1.0394), new MathContext(8, RoundingMode.HALF_UP));
              System.out.println("After division, with normal rounding, val1 =" + val1 + ", rounding using math context, val2=" + val2);

      Try the above code in a simple java program

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      185681.53420000 (in case of multiplication)
      171871.27188763 (in case of division)
      ACTUAL -
      185681.53 (in case of multiplication)
      171871.27 (in case of division)

      ---------- BEGIN SOURCE ----------
      import java.math.BigDecimal;
      import java.math.MathContext;
      import java.math.RoundingMode;

      public class MathContextIssues {

          public static void main(String[] args) {
              // TODO Auto-generated method stub
              // Multiplication -- using setScale
              BigDecimal quantity = new BigDecimal(178643);
              BigDecimal val1 = quantity.multiply(new BigDecimal(1.0394)).setScale(8, BigDecimal.ROUND_HALF_UP);
              // Multiplication -- precision by using MathContext.
              BigDecimal val2 = quantity.multiply(new BigDecimal(1.0394), new MathContext(8, RoundingMode.HALF_UP));
              System.out.println("After multiplication, with normal rounding, val1 =" + val1
                      + ", rounding using math context, val2=" + val2);
              // Division -- using setScale -- This produces an error:
              // "java.lang.ArithmeticException: Non-terminating decimal expansion; no exact
              // representable decimal result."
              // val1 = quantity.divide(new BigDecimal(1.0394)).setScale(8,
              // BigDecimal.ROUND_HALF_UP);
              // Division -- passing the scale and rounding mode - works fine.
              val1 = quantity.divide(new BigDecimal(1.0394), 8, RoundingMode.HALF_UP);
              // Division -- precision by using MathContext.
              val2 = quantity.divide(new BigDecimal(1.0394), new MathContext(8, RoundingMode.HALF_UP));
              System.out.println(
                      "After division, with normal rounding, val1 =" + val1 + ", rounding using math context, val2=" + val2);
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      .setScale(8, BigDecimal.ROUND_HALF_UP) // for multiplication
      .divide(new BigDecimal(1.0394), 8, RoundingMode.HALF_UP); // for division

      FREQUENCY : always


            tongwan Andrew Wang
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: