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