6876282: BigDecimal's divide(BigDecimal bd, RoundingFormat r) produces incorrect result
Reviewed-by: darcy
--- 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;
}