6876282: BigDecimal's divide(BigDecimal bd, RoundingFormat r) produces incorrect result
authorxlu
Thu, 27 Aug 2009 18:00:16 -0700
changeset 3710 65a5d7914736
parent 3709 e7cf22d025bb
child 3711 675253c23780
6876282: BigDecimal's divide(BigDecimal bd, RoundingFormat r) produces incorrect result Reviewed-by: darcy
jdk/src/share/classes/java/math/BigDecimal.java
jdk/test/java/math/BigDecimal/DivideTests.java
--- a/jdk/src/share/classes/java/math/BigDecimal.java	Thu Aug 27 11:48:35 2009 -0700
+++ b/jdk/src/share/classes/java/math/BigDecimal.java	Thu Aug 27 18:00:16 2009 -0700
@@ -315,6 +315,10 @@
         new BigDecimal(BigInteger.ZERO, 0, 15, 1),
     };
 
+    // Half of Long.MIN_VALUE & Long.MAX_VALUE.
+    private static final long HALF_LONG_MAX_VALUE = Long.MAX_VALUE / 2;
+    private static final long HALF_LONG_MIN_VALUE = Long.MIN_VALUE / 2;
+
     // Constants
     /**
      * The value 0, with a scale of 0.
@@ -1455,10 +1459,15 @@
             } else if (roundingMode == ROUND_FLOOR) {   // Towards -infinity
                 increment = (qsign < 0);
             } else {
-                if (isLongDivision || ldivisor != INFLATED)
-                    cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
-                else
+                if (isLongDivision || ldivisor != INFLATED) {
+                    if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
+                        cmpFracHalf = 1;    // 2 * r can't fit into long
+                    } else {
+                        cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
+                    }
+                } else {
                     cmpFracHalf = mr.compareHalf(mdivisor);
+                }
                 if (cmpFracHalf < 0)
                     increment = false;     // We're closer to higher digit
                 else if (cmpFracHalf > 0)  // We're closer to lower digit
--- a/jdk/test/java/math/BigDecimal/DivideTests.java	Thu Aug 27 11:48:35 2009 -0700
+++ b/jdk/test/java/math/BigDecimal/DivideTests.java	Thu Aug 27 18:00:16 2009 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 4851776 4907265 6177836
+ * @bug 4851776 4907265 6177836 6876282
  * @summary Some tests for the divide methods.
  * @author Joseph D. Darcy
  * @compile -source 1.5 DivideTests.java
@@ -328,6 +328,35 @@
             }
         }
 
+        // 6876282
+        BigDecimal[][] testCases2 = {
+            // { dividend, divisor, expected quotient }
+            { new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },
+            { new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),
+              new BigDecimal(441) },
+            { new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),
+              new BigDecimal("0.000115309916") },
+            { new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),
+              new BigDecimal(4) },
+            { new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),
+              new BigDecimal(4) },
+            { new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),
+              new BigDecimal(5) },
+            { new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),
+              new BigDecimal(4) },
+            { new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),
+              new BigDecimal(4) },
+        };
+
+        for (BigDecimal test[] : testCases2) {
+            BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);
+            if (!quo.equals(test[2])) {
+                failures++;
+                System.err.println("Unexpected quotient from " + test[0] + " / " + test[1] +
+                                   " rounding mode HALF_UP" +
+                                   "; expected " + test[2] + " got " + quo);
+            }
+        }
         return failures;
     }