More stuff. Sorry for not sending this BigDecimal stuff all at once but my test cases are small and I prefer to get the stuff committed once its been tested. Also helps me use JAPI to determine what needs to be done.
2006-02-27 Anthony Balkissoon <[EMAIL PROTECTED]> * java/math/BigDecimal.java: Replaced occurences of BigInteger.valueOf with BigInteger.ZERO, BigInteger.ONE, BigInteger.TEN where appropriate. (add(BigDecimal, MathContext)): New method. (subtract(BigDecimal, MathContext)): Likewise. (precision): Fixed to correctly handle BigIntegers with more than 19 digits. (pow(int, MathContext)): New method. --Tony
Index: java/math/BigDecimal.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/math/BigDecimal.java,v retrieving revision 1.17.2.12 diff -u -r1.17.2.12 BigDecimal.java --- java/math/BigDecimal.java 27 Feb 2006 19:49:07 -0000 1.17.2.12 +++ java/math/BigDecimal.java 27 Feb 2006 21:31:00 -0000 @@ -49,21 +49,21 @@ * @since 1.5 */ public static final BigDecimal ZERO = - new BigDecimal (BigInteger.valueOf (0), 0); + new BigDecimal (BigInteger.ZERO, 0); /** * The constant one as a BigDecimal with scale zero. * @since 1.5 */ public static final BigDecimal ONE = - new BigDecimal (BigInteger.valueOf (1), 0); + new BigDecimal (BigInteger.ONE, 0); /** * The constant ten as a BigDecimal with scale zero. * @since 1.5 */ public static final BigDecimal TEN = - new BigDecimal (BigInteger.valueOf (10), 0); + new BigDecimal (BigInteger.TEN, 0); public static final int ROUND_UP = 0; public static final int ROUND_DOWN = 1; @@ -603,18 +603,48 @@ BigInteger op1 = intVal; BigInteger op2 = val.intVal; if (scale < val.scale) - op1 = op1.multiply (BigInteger.valueOf (10).pow (val.scale - scale)); + op1 = op1.multiply (BigInteger.TEN.pow (val.scale - scale)); else if (scale > val.scale) - op2 = op2.multiply (BigInteger.valueOf (10).pow (scale - val.scale)); + op2 = op2.multiply (BigInteger.TEN.pow (scale - val.scale)); return new BigDecimal (op1.add (op2), Math.max (scale, val.scale)); } + + /** + * Returns a BigDecimal whose value is found first by calling the + * method add(val) and then by rounding according to the MathContext mc. + * @param val the augend + * @param mc the MathContext for rounding + * @throws ArithmeticException if the value is inexact but the rounding is + * RoundingMode.UNNECESSARY + * @return <code>this</code> + <code>val</code>, rounded if need be + * @since 1.5 + */ + public BigDecimal add (BigDecimal val, MathContext mc) + { + return add(val).round(mc); + } public BigDecimal subtract (BigDecimal val) { return this.add(val.negate()); } + /** + * Returns a BigDecimal whose value is found first by calling the + * method subtract(val) and then by rounding according to the MathContext mc. + * @param val the subtrahend + * @param mc the MathContext for rounding + * @throws ArithmeticException if the value is inexact but the rounding is + * RoundingMode.UNNECESSARY + * @return <code>this</code> - <code>val</code>, rounded if need be + * @since 1.5 + */ + public BigDecimal subtract (BigDecimal val, MathContext mc) + { + return subtract(val).round(mc); + } + public BigDecimal multiply (BigDecimal val) { return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale); @@ -661,11 +691,11 @@ { // Effectively increase the scale of val to avoid an // ArithmeticException for a negative power. - valIntVal = valIntVal.multiply (BigInteger.valueOf (10).pow (-power)); + valIntVal = valIntVal.multiply (BigInteger.TEN.pow (-power)); power = 0; } - BigInteger dividend = intVal.multiply (BigInteger.valueOf (10).pow (power)); + BigInteger dividend = intVal.multiply (BigInteger.TEN.pow (power)); BigInteger parts[] = dividend.divideAndRemainder (valIntVal); @@ -674,7 +704,7 @@ return new BigDecimal (unrounded, newScale); if (roundingMode == ROUND_UNNECESSARY) - throw new ArithmeticException ("newScale is not large enough"); + throw new ArithmeticException ("Rounding necessary"); int sign = intVal.signum () * valIntVal.signum (); @@ -726,9 +756,9 @@ return intVal.compareTo (val.intVal); BigInteger thisParts[] = - intVal.divideAndRemainder (BigInteger.valueOf (10).pow (scale)); + intVal.divideAndRemainder (BigInteger.TEN.pow (scale)); BigInteger valParts[] = - val.intVal.divideAndRemainder (BigInteger.valueOf (10).pow (val.scale)); + val.intVal.divideAndRemainder (BigInteger.TEN.pow (val.scale)); int compare; if ((compare = thisParts[0].compareTo (valParts[0])) != 0) @@ -737,15 +767,15 @@ // quotients are the same, so compare remainders // remove trailing zeros - if (thisParts[1].equals (BigInteger.valueOf (0)) == false) - while (thisParts[1].mod (BigInteger.valueOf (10)).equals - (BigInteger.valueOf (0))) - thisParts[1] = thisParts[1].divide (BigInteger.valueOf (10)); + if (thisParts[1].equals (BigInteger.ZERO) == false) + while (thisParts[1].mod (BigInteger.TEN).equals + (BigInteger.ZERO)) + thisParts[1] = thisParts[1].divide (BigInteger.TEN); // again... - if (valParts[1].equals(BigInteger.valueOf (0)) == false) - while (valParts[1].mod (BigInteger.valueOf (10)).equals - (BigInteger.valueOf (0))) - valParts[1] = valParts[1].divide (BigInteger.valueOf (10)); + if (valParts[1].equals(BigInteger.ZERO) == false) + while (valParts[1].mod (BigInteger.TEN).equals + (BigInteger.ZERO)) + valParts[1] = valParts[1].divide (BigInteger.TEN); // and compare them return thisParts[1].compareTo (valParts[1]); @@ -799,7 +829,7 @@ return new BigDecimal (intVal, scale - n); return new BigDecimal (intVal.multiply - (BigInteger.valueOf (10).pow (n - scale)), 0); + (BigInteger.TEN.pow (n - scale)), 0); } public int signum () @@ -887,8 +917,7 @@ // Make a new BigDecimal which is the correct power of 10 to chop off // the required number of digits and then call divide. - BigDecimal div = - new BigDecimal(BigInteger.valueOf((long)Math.pow(10, numToChop))); + BigDecimal div = new BigDecimal(BigInteger.TEN.pow(numToChop)); BigDecimal rounded = divide(div, scale, mc.getRoundingMode().ordinal()); rounded.scale -= numToChop; rounded.precision = mcPrecision; @@ -904,9 +933,32 @@ public int precision() { if (precision == 0) - precision = numDigitsInLong(intVal.longValue()); + { + precision = numDigitsInLong(intVal.longValue()); + // If numDigitsInLong returns 19 then we use numDigitsInBigInteger + // to determine if there are actually more than 19 digits in intVal. + if (precision == 19) + precision = numDigitsInBigInteger(intVal); + } + return precision; } + + /** + * This method is used to determine the precision of BigIntegers with 19 or + * more digits. + * @param b the BigInteger + * @return the number of digits in <code>b</code> + */ + int numDigitsInBigInteger(BigInteger b) + { + int i = 19; + BigInteger comp = BigInteger.TEN.pow(i); + while (b.compareTo(comp) >= 0) + comp = BigInteger.TEN.pow(++i); + + return i; + } /** * This method determines the number of digits in the long value l. @@ -1204,9 +1256,9 @@ // If scale > 0 then we must divide, if scale > 0 then we must multiply, // and if scale is zero then we just return intVal; if (scale > 0) - return intVal.divide (BigInteger.valueOf (10).pow (scale)); + return intVal.divide (BigInteger.TEN.pow (scale)); else if (scale < 0) - return intVal.multiply(BigInteger.valueOf(10).pow(-scale)); + return intVal.multiply(BigInteger.TEN.pow(-scale)); return intVal; } @@ -1222,14 +1274,14 @@ { // If we have to divide, we must check if the result is exact. BigInteger[] result = - intVal.divideAndRemainder(BigInteger.valueOf(10).pow(scale)); + intVal.divideAndRemainder(BigInteger.TEN.pow(scale)); if (result[1].equals(BigInteger.ZERO)) return result[0]; throw new ArithmeticException("No exact BigInteger representation"); } else if (scale < 0) // If we're multiplying instead, then we needn't check for exactness. - return intVal.multiply(BigInteger.valueOf(10).pow(-scale)); + return intVal.multiply(BigInteger.TEN.pow(-scale)); // If the scale is zero we can simply return intVal. return intVal; } @@ -1339,6 +1391,23 @@ } /** + * Returns a BigDecimal whose value is determined by first calling pow(n) + * and then by rounding according to the MathContext mc. + * @param n the power + * @param mc the MathContext + * @return the new BigDecimal + * @throws ArithmeticException if n < 0 or n > 999999999 or if the result is + * inexact but the rounding is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal pow(int n, MathContext mc) + { + // FIXME: The specs claim to use the X3.274-1996 algorithm. We + // currently do not. + return pow(n).round(mc); + } + + /** * Returns a BigDecimal whose value is the absolute value of this BigDecimal * with rounding according to the given MathContext. * @param mc the MathContext