6378503: In java.math.BigDecimal, division by one returns zero
6446965: Using BigDecimal.divideToIntegralValue with extreme scales can lead to an incorrect result Fix overflow of ints and ensure appropriate values passed to checkScaleNonZero() Reviewed-by: darcy, martin
This commit is contained in:
parent
6d2de008d7
commit
6c5c2d745a
@ -2659,28 +2659,32 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||||||
if (ys == 0)
|
if (ys == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
int sdiff = this.scale - val.scale;
|
long sdiff = (long)this.scale - val.scale;
|
||||||
if (sdiff != 0) {
|
if (sdiff != 0) {
|
||||||
// Avoid matching scales if the (adjusted) exponents differ
|
// Avoid matching scales if the (adjusted) exponents differ
|
||||||
int xae = this.precision() - this.scale; // [-1]
|
long xae = (long)this.precision() - this.scale; // [-1]
|
||||||
int yae = val.precision() - val.scale; // [-1]
|
long yae = (long)val.precision() - val.scale; // [-1]
|
||||||
if (xae < yae)
|
if (xae < yae)
|
||||||
return -1;
|
return -1;
|
||||||
if (xae > yae)
|
if (xae > yae)
|
||||||
return 1;
|
return 1;
|
||||||
BigInteger rb = null;
|
BigInteger rb = null;
|
||||||
if (sdiff < 0) {
|
if (sdiff < 0) {
|
||||||
if ( (xs == INFLATED ||
|
// The cases sdiff <= Integer.MIN_VALUE intentionally fall through.
|
||||||
(xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) &&
|
if ( sdiff > Integer.MIN_VALUE &&
|
||||||
|
(xs == INFLATED ||
|
||||||
|
(xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) &&
|
||||||
ys == INFLATED) {
|
ys == INFLATED) {
|
||||||
rb = bigMultiplyPowerTen(-sdiff);
|
rb = bigMultiplyPowerTen((int)-sdiff);
|
||||||
return rb.compareMagnitude(val.intVal);
|
return rb.compareMagnitude(val.intVal);
|
||||||
}
|
}
|
||||||
} else { // sdiff > 0
|
} else { // sdiff > 0
|
||||||
if ( (ys == INFLATED ||
|
// The cases sdiff > Integer.MAX_VALUE intentionally fall through.
|
||||||
(ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) &&
|
if ( sdiff <= Integer.MAX_VALUE &&
|
||||||
|
(ys == INFLATED ||
|
||||||
|
(ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) &&
|
||||||
xs == INFLATED) {
|
xs == INFLATED) {
|
||||||
rb = val.bigMultiplyPowerTen(sdiff);
|
rb = val.bigMultiplyPowerTen((int)sdiff);
|
||||||
return this.intVal.compareMagnitude(rb);
|
return this.intVal.compareMagnitude(rb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4545,7 +4549,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||||||
if(cmp > 0) { // satisfy constraint (b)
|
if(cmp > 0) { // satisfy constraint (b)
|
||||||
yscale -= 1; // [that is, divisor *= 10]
|
yscale -= 1; // [that is, divisor *= 10]
|
||||||
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
||||||
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
|
if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
|
||||||
// assert newScale >= xscale
|
// assert newScale >= xscale
|
||||||
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
||||||
long scaledXs;
|
long scaledXs;
|
||||||
@ -4626,7 +4630,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||||||
// return BigDecimal object whose scale will be set to 'scl'.
|
// return BigDecimal object whose scale will be set to 'scl'.
|
||||||
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
||||||
BigDecimal quotient;
|
BigDecimal quotient;
|
||||||
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
|
if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
|
||||||
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
||||||
long scaledXs;
|
long scaledXs;
|
||||||
if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) {
|
if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) {
|
||||||
@ -4673,7 +4677,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||||||
// return BigDecimal object whose scale will be set to 'scl'.
|
// return BigDecimal object whose scale will be set to 'scl'.
|
||||||
BigDecimal quotient;
|
BigDecimal quotient;
|
||||||
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
||||||
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
|
if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
|
||||||
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
||||||
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
||||||
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
|
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
|
||||||
@ -4714,7 +4718,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||||||
// return BigDecimal object whose scale will be set to 'scl'.
|
// return BigDecimal object whose scale will be set to 'scl'.
|
||||||
BigDecimal quotient;
|
BigDecimal quotient;
|
||||||
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
||||||
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
|
if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
|
||||||
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
||||||
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
||||||
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
|
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
|
||||||
@ -4745,7 +4749,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
|||||||
// return BigDecimal object whose scale will be set to 'scl'.
|
// return BigDecimal object whose scale will be set to 'scl'.
|
||||||
BigDecimal quotient;
|
BigDecimal quotient;
|
||||||
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
|
||||||
if (checkScaleNonZero((long) mcp + yscale) > xscale) {
|
if (checkScaleNonZero((long) mcp + yscale - xscale) > 0) {
|
||||||
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
int raise = checkScaleNonZero((long) mcp + yscale - xscale);
|
||||||
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
BigInteger rb = bigMultiplyPowerTen(xs,raise);
|
||||||
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
|
quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
|
||||||
|
@ -2109,7 +2109,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
|||||||
// This is a quick way to approximate the size of the result,
|
// This is a quick way to approximate the size of the result,
|
||||||
// similar to doing log2[n] * exponent. This will give an upper bound
|
// similar to doing log2[n] * exponent. This will give an upper bound
|
||||||
// of how big the result can be, and which algorithm to use.
|
// of how big the result can be, and which algorithm to use.
|
||||||
int scaleFactor = remainingBits * exponent;
|
long scaleFactor = (long)remainingBits * exponent;
|
||||||
|
|
||||||
// Use slightly different algorithms for small and large operands.
|
// Use slightly different algorithms for small and large operands.
|
||||||
// See if the result will safely fit into a long. (Largest 2^63-1)
|
// See if the result will safely fit into a long. (Largest 2^63-1)
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 4904082 4917089 6337226
|
* @bug 4904082 4917089 6337226 6378503
|
||||||
* @summary Tests that integral division and related methods return the proper result and scale.
|
* @summary Tests that integral division and related methods return the proper result and scale.
|
||||||
* @author Joseph D. Darcy
|
* @author Joseph D. Darcy
|
||||||
*/
|
*/
|
||||||
@ -47,6 +47,9 @@ public class IntegralDivisionTests {
|
|||||||
{new BigDecimal("400e1"), new BigDecimal("5"), new BigDecimal("80e1")},
|
{new BigDecimal("400e1"), new BigDecimal("5"), new BigDecimal("80e1")},
|
||||||
{new BigDecimal("400e1"), new BigDecimal("4.999999999"), new BigDecimal("8e2")},
|
{new BigDecimal("400e1"), new BigDecimal("4.999999999"), new BigDecimal("8e2")},
|
||||||
{new BigDecimal("40e2"), new BigDecimal("5"), new BigDecimal("8e2")},
|
{new BigDecimal("40e2"), new BigDecimal("5"), new BigDecimal("8e2")},
|
||||||
|
{BigDecimal.valueOf(1, Integer.MIN_VALUE),
|
||||||
|
BigDecimal.valueOf(1, -(Integer.MAX_VALUE & 0x7fffff00)),
|
||||||
|
BigDecimal.valueOf(1, -256)},
|
||||||
};
|
};
|
||||||
|
|
||||||
for(BigDecimal [] testCase: moreTestCases) {
|
for(BigDecimal [] testCase: moreTestCases) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user