diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/java/math/BigDecimal.java | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/java/math/BigDecimal.java')
-rw-r--r-- | libjava/classpath/java/math/BigDecimal.java | 1559 |
1 files changed, 1559 insertions, 0 deletions
diff --git a/libjava/classpath/java/math/BigDecimal.java b/libjava/classpath/java/math/BigDecimal.java new file mode 100644 index 000000000..7f4546cda --- /dev/null +++ b/libjava/classpath/java/math/BigDecimal.java @@ -0,0 +1,1559 @@ +/* java.math.BigDecimal -- Arbitrary precision decimals. + Copyright (C) 1999, 2000, 2001, 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.math; + +import gnu.java.lang.CPStringBuilder; + +public class BigDecimal extends Number implements Comparable<BigDecimal> +{ + private BigInteger intVal; + private int scale; + private int precision = 0; + private static final long serialVersionUID = 6108874887143696463L; + + /** + * The constant zero as a BigDecimal with scale zero. + * @since 1.5 + */ + public static final BigDecimal ZERO = + 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.ONE, 0); + + /** + * The constant ten as a BigDecimal with scale zero. + * @since 1.5 + */ + public static final BigDecimal TEN = + new BigDecimal (BigInteger.TEN, 0); + + public static final int ROUND_UP = 0; + public static final int ROUND_DOWN = 1; + public static final int ROUND_CEILING = 2; + public static final int ROUND_FLOOR = 3; + public static final int ROUND_HALF_UP = 4; + public static final int ROUND_HALF_DOWN = 5; + public static final int ROUND_HALF_EVEN = 6; + public static final int ROUND_UNNECESSARY = 7; + + /** + * Constructs a new BigDecimal whose unscaled value is val and whose + * scale is zero. + * @param val the value of the new BigDecimal + * @since 1.5 + */ + public BigDecimal (int val) + { + this.intVal = BigInteger.valueOf(val); + this.scale = 0; + } + + /** + * Constructs a BigDecimal using the BigDecimal(int) constructor and then + * rounds according to the MathContext. + * @param val the value for the initial (unrounded) BigDecimal + * @param mc the MathContext specifying the rounding + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal (int val, MathContext mc) + { + this (val); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + } + + /** + * Constructs a new BigDecimal whose unscaled value is val and whose + * scale is zero. + * @param val the value of the new BigDecimal + */ + public BigDecimal (long val) + { + this.intVal = BigInteger.valueOf(val); + this.scale = 0; + } + + /** + * Constructs a BigDecimal from the long in the same way as BigDecimal(long) + * and then rounds according to the MathContext. + * @param val the long from which we create the initial BigDecimal + * @param mc the MathContext that specifies the rounding behaviour + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal (long val, MathContext mc) + { + this(val); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + } + + /** + * Constructs a BigDecimal whose value is given by num rounded according to + * mc. Since num is already a BigInteger, the rounding refers only to the + * precision setting in mc, if mc.getPrecision() returns an int lower than + * the number of digits in num, then rounding is necessary. + * @param num the unscaledValue, before rounding + * @param mc the MathContext that specifies the precision + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * * @since 1.5 + */ + public BigDecimal (BigInteger num, MathContext mc) + { + this (num, 0); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + } + + /** + * Constructs a BigDecimal from the String val according to the same + * rules as the BigDecimal(String) constructor and then rounds + * according to the MathContext mc. + * @param val the String from which we construct the initial BigDecimal + * @param mc the MathContext that specifies the rounding + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal (String val, MathContext mc) + { + this (val); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + } + + /** + * Constructs a BigDecimal whose unscaled value is num and whose + * scale is zero. + * @param num the value of the new BigDecimal + */ + public BigDecimal (BigInteger num) + { + this (num, 0); + } + + /** + * Constructs a BigDecimal whose unscaled value is num and whose + * scale is scale. + * @param num + * @param scale + */ + public BigDecimal (BigInteger num, int scale) + { + this.intVal = num; + this.scale = scale; + } + + /** + * Constructs a BigDecimal using the BigDecimal(BigInteger, int) + * constructor and then rounds according to the MathContext. + * @param num the unscaled value of the unrounded BigDecimal + * @param scale the scale of the unrounded BigDecimal + * @param mc the MathContext specifying the rounding + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal (BigInteger num, int scale, MathContext mc) + { + this (num, scale); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + } + + /** + * Constructs a BigDecimal in the same way as BigDecimal(double) and then + * rounds according to the MathContext. + * @param num the double from which the initial BigDecimal is created + * @param mc the MathContext that specifies the rounding behaviour + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal (double num, MathContext mc) + { + this (num); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + } + + public BigDecimal (double num) throws NumberFormatException + { + if (Double.isInfinite (num) || Double.isNaN (num)) + throw new NumberFormatException ("invalid argument: " + num); + // Note we can't convert NUM to a String and then use the + // String-based constructor. The BigDecimal documentation makes + // it clear that the two constructors work differently. + + final int mantissaBits = 52; + final int exponentBits = 11; + final long mantMask = (1L << mantissaBits) - 1; + final long expMask = (1L << exponentBits) - 1; + + long bits = Double.doubleToLongBits (num); + long mantissa = bits & mantMask; + long exponent = (bits >>> mantissaBits) & expMask; + boolean denormal = exponent == 0; + + // Correct the exponent for the bias. + exponent -= denormal ? 1022 : 1023; + + // Now correct the exponent to account for the bits to the right + // of the decimal. + exponent -= mantissaBits; + // Ordinary numbers have an implied leading `1' bit. + if (! denormal) + mantissa |= (1L << mantissaBits); + + // Shave off factors of 10. + while (exponent < 0 && (mantissa & 1) == 0) + { + ++exponent; + mantissa >>= 1; + } + + intVal = BigInteger.valueOf (bits < 0 ? - mantissa : mantissa); + if (exponent < 0) + { + // We have MANTISSA * 2 ^ (EXPONENT). + // Since (1/2)^N == 5^N * 10^-N we can easily convert this + // into a power of 10. + scale = (int) (- exponent); + BigInteger mult = BigInteger.valueOf (5).pow (scale); + intVal = intVal.multiply (mult); + } + else + { + intVal = intVal.shiftLeft ((int) exponent); + scale = 0; + } + } + + /** + * Constructs a BigDecimal from the char subarray and rounding + * according to the MathContext. + * @param in the char array + * @param offset the start of the subarray + * @param len the length of the subarray + * @param mc the MathContext for rounding + * @throws NumberFormatException if the char subarray is not a valid + * BigDecimal representation + * @throws ArithmeticException if the result is inexact but the rounding + * mode is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal(char[] in, int offset, int len, MathContext mc) + { + this(in, offset, len); + // If mc has precision other than zero then we must round. + if (mc.getPrecision() != 0) + { + BigDecimal temp = this.round(mc); + this.intVal = temp.intVal; + this.scale = temp.scale; + this.precision = temp.precision; + } + } + + /** + * Constructs a BigDecimal from the char array and rounding according + * to the MathContext. + * @param in the char array + * @param mc the MathContext + * @throws NumberFormatException if <code>in</code> is not a valid BigDecimal + * representation + * @throws ArithmeticException if the result is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal(char[] in, MathContext mc) + { + this(in, 0, in.length); + // If mc has precision other than zero then we must round. + if (mc.getPrecision() != 0) + { + BigDecimal temp = this.round(mc); + this.intVal = temp.intVal; + this.scale = temp.scale; + this.precision = temp.precision; + } + } + + /** + * Constructs a BigDecimal from the given char array, accepting the same + * sequence of characters as the BigDecimal(String) constructor. + * @param in the char array + * @throws NumberFormatException if <code>in</code> is not a valid BigDecimal + * representation + * @since 1.5 + */ + public BigDecimal(char[] in) + { + this(in, 0, in.length); + } + + /** + * Constructs a BigDecimal from a char subarray, accepting the same sequence + * of characters as the BigDecimal(String) constructor. + * @param in the char array + * @param offset the start of the subarray + * @param len the length of the subarray + * @throws NumberFormatException if <code>in</code> is not a valid + * BigDecimal representation. + * @since 1.5 + */ + public BigDecimal(char[] in, int offset, int len) + { + // start is the index into the char array where the significand starts + int start = offset; + // end is one greater than the index of the last character used + int end = offset + len; + // point is the index into the char array where the exponent starts + // (or, if there is no exponent, this is equal to end) + int point = offset; + // dot is the index into the char array where the decimal point is + // found, or -1 if there is no decimal point + int dot = -1; + + // The following examples show what these variables mean. Note that + // point and dot don't yet have the correct values, they will be + // properly assigned in a loop later on in this method. + // + // Example 1 + // + // + 1 0 2 . 4 6 9 + // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + // + // offset = 2, len = 8, start = 3, dot = 6, point = end = 10 + // + // Example 2 + // + // + 2 3 4 . 6 1 3 E - 1 + // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + // + // offset = 2, len = 11, start = 3, dot = 6, point = 10, end = 13 + // + // Example 3 + // + // - 1 2 3 4 5 e 7 + // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + // + // offset = 2, len = 8, start = 3, dot = -1, point = 8, end = 10 + + // Determine the sign of the number. + boolean negative = false; + if (in[offset] == '+') + { + ++start; + ++point; + } + else if (in[offset] == '-') + { + ++start; + ++point; + negative = true; + } + + // Check each character looking for the decimal point and the + // start of the exponent. + while (point < end) + { + char c = in[point]; + if (c == '.') + { + // If dot != -1 then we've seen more than one decimal point. + if (dot != -1) + throw new NumberFormatException("multiple `.'s in number"); + dot = point; + } + // Break when we reach the start of the exponent. + else if (c == 'e' || c == 'E') + break; + // Throw an exception if the character was not a decimal or an + // exponent and is not a digit. + else if (!Character.isDigit(c)) + throw new NumberFormatException("unrecognized character at " + point + + ": " + c); + ++point; + } + + // val is a StringBuilder from which we'll create a BigInteger + // which will be the unscaled value for this BigDecimal + CPStringBuilder val = new CPStringBuilder(point - start - 1); + if (dot != -1) + { + // If there was a decimal we must combine the two parts that + // contain only digits and we must set the scale properly. + val.append(in, start, dot - start); + val.append(in, dot + 1, point - dot - 1); + scale = point - 1 - dot; + } + else + { + // If there was no decimal then the unscaled value is just the number + // formed from all the digits and the scale is zero. + val.append(in, start, point - start); + scale = 0; + } + if (val.length() == 0) + throw new NumberFormatException("no digits seen"); + + // Prepend a negative sign if necessary. + if (negative) + val.insert(0, '-'); + intVal = new BigInteger(val.toString()); + + // Now parse exponent. + // If point < end that means we broke out of the previous loop when we + // saw an 'e' or an 'E'. + if (point < end) + { + point++; + // Ignore a '+' sign. + if (in[point] == '+') + point++; + + // Throw an exception if there were no digits found after the 'e' + // or 'E'. + if (point >= end) + throw new NumberFormatException("no exponent following e or E"); + + try + { + // Adjust the scale according to the exponent. + // Remember that the value of a BigDecimal is + // unscaledValue x Math.pow(10, -scale) + scale -= Integer.parseInt(new String(in, point, end - point)); + } + catch (NumberFormatException ex) + { + throw new NumberFormatException("malformed exponent"); + } + } + } + + public BigDecimal (String num) throws NumberFormatException + { + int len = num.length(); + int start = 0, point = 0; + int dot = -1; + boolean negative = false; + if (num.charAt(0) == '+') + { + ++start; + ++point; + } + else if (num.charAt(0) == '-') + { + ++start; + ++point; + negative = true; + } + + while (point < len) + { + char c = num.charAt (point); + if (c == '.') + { + if (dot >= 0) + throw new NumberFormatException ("multiple `.'s in number"); + dot = point; + } + else if (c == 'e' || c == 'E') + break; + else if (Character.digit (c, 10) < 0) + throw new NumberFormatException ("unrecognized character: " + c); + ++point; + } + + String val; + if (dot >= 0) + { + val = num.substring (start, dot) + num.substring (dot + 1, point); + scale = point - 1 - dot; + } + else + { + val = num.substring (start, point); + scale = 0; + } + if (val.length () == 0) + throw new NumberFormatException ("no digits seen"); + + if (negative) + val = "-" + val; + intVal = new BigInteger (val); + + // Now parse exponent. + if (point < len) + { + point++; + if (num.charAt(point) == '+') + point++; + + if (point >= len ) + throw new NumberFormatException ("no exponent following e or E"); + + try + { + scale -= Integer.parseInt (num.substring (point)); + } + catch (NumberFormatException ex) + { + throw new NumberFormatException ("malformed exponent"); + } + } + } + + public static BigDecimal valueOf (long val) + { + return valueOf (val, 0); + } + + public static BigDecimal valueOf (long val, int scale) + throws NumberFormatException + { + if ((scale == 0) && ((int)val == val)) + switch ((int) val) + { + case 0: + return ZERO; + case 1: + return ONE; + } + + return new BigDecimal (BigInteger.valueOf (val), scale); + } + + public BigDecimal add (BigDecimal val) + { + // For addition, need to line up decimals. Note that the movePointRight + // method cannot be used for this as it might return a BigDecimal with + // scale == 0 instead of the scale we need. + BigInteger op1 = intVal; + BigInteger op2 = val.intVal; + if (scale < val.scale) + op1 = op1.multiply (BigInteger.TEN.pow (val.scale - scale)); + else if (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); + } + + /** + * Returns a BigDecimal whose value is (this x val) before it is rounded + * according to the MathContext mc. + * @param val the multiplicand + * @param mc the MathContext for rounding + * @return a new BigDecimal with value approximately (this x val) + * @throws ArithmeticException if the value is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal multiply (BigDecimal val, MathContext mc) + { + return multiply(val).round(mc); + } + + public BigDecimal divide (BigDecimal val, int roundingMode) + throws ArithmeticException, IllegalArgumentException + { + return divide (val, scale, roundingMode); + } + + /** + * Returns a BigDecimal whose value is (this / val), with the specified scale + * and rounding according to the RoundingMode + * @param val the divisor + * @param scale the scale of the BigDecimal returned + * @param roundingMode the rounding mode to use + * @return a BigDecimal whose value is approximately (this / val) + * @throws ArithmeticException if divisor is zero or the rounding mode is + * UNNECESSARY but the specified scale cannot represent the value exactly + * @since 1.5 + */ + public BigDecimal divide(BigDecimal val, + int scale, RoundingMode roundingMode) + { + return divide (val, scale, roundingMode.ordinal()); + } + + /** + * Returns a BigDecimal whose value is (this / val) rounded according to the + * RoundingMode + * @param val the divisor + * @param roundingMode the rounding mode to use + * @return a BigDecimal whose value is approximately (this / val) + * @throws ArithmeticException if divisor is zero or the rounding mode is + * UNNECESSARY but the specified scale cannot represent the value exactly + */ + public BigDecimal divide (BigDecimal val, RoundingMode roundingMode) + { + return divide (val, scale, roundingMode.ordinal()); + } + + public BigDecimal divide(BigDecimal val, int newScale, int roundingMode) + throws ArithmeticException, IllegalArgumentException + { + if (roundingMode < 0 || roundingMode > 7) + throw + new IllegalArgumentException("illegal rounding mode: " + roundingMode); + + if (intVal.signum () == 0) // handle special case of 0.0/0.0 + return newScale == 0 ? ZERO : new BigDecimal (ZERO.intVal, newScale); + + // Ensure that pow gets a non-negative value. + BigInteger valIntVal = val.intVal; + int power = newScale - (scale - val.scale); + if (power < 0) + { + // Effectively increase the scale of val to avoid an + // ArithmeticException for a negative power. + valIntVal = valIntVal.multiply (BigInteger.TEN.pow (-power)); + power = 0; + } + + BigInteger dividend = intVal.multiply (BigInteger.TEN.pow (power)); + + BigInteger parts[] = dividend.divideAndRemainder (valIntVal); + + BigInteger unrounded = parts[0]; + if (parts[1].signum () == 0) // no remainder, no rounding necessary + return new BigDecimal (unrounded, newScale); + + if (roundingMode == ROUND_UNNECESSARY) + throw new ArithmeticException ("Rounding necessary"); + + int sign = intVal.signum () * valIntVal.signum (); + + if (roundingMode == ROUND_CEILING) + roundingMode = (sign > 0) ? ROUND_UP : ROUND_DOWN; + else if (roundingMode == ROUND_FLOOR) + roundingMode = (sign < 0) ? ROUND_UP : ROUND_DOWN; + else + { + // half is -1 if remainder*2 < positive intValue (*power), 0 if equal, + // 1 if >. This implies that the remainder to round is less than, + // equal to, or greater than half way to the next digit. + BigInteger posRemainder + = parts[1].signum () < 0 ? parts[1].negate() : parts[1]; + valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal; + int half = posRemainder.shiftLeft(1).compareTo(valIntVal); + + switch(roundingMode) + { + case ROUND_HALF_UP: + roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP; + break; + case ROUND_HALF_DOWN: + roundingMode = (half > 0) ? ROUND_UP : ROUND_DOWN; + break; + case ROUND_HALF_EVEN: + if (half < 0) + roundingMode = ROUND_DOWN; + else if (half > 0) + roundingMode = ROUND_UP; + else if (unrounded.testBit(0)) // odd, then ROUND_HALF_UP + roundingMode = ROUND_UP; + else // even, ROUND_HALF_DOWN + roundingMode = ROUND_DOWN; + break; + } + } + + if (roundingMode == ROUND_UP) + unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1)); + + // roundingMode == ROUND_DOWN + return new BigDecimal (unrounded, newScale); + } + + /** + * Performs division, if the resulting quotient requires rounding + * (has a nonterminating decimal expansion), + * an ArithmeticException is thrown. + * #see divide(BigDecimal, int, int) + * @since 1.5 + */ + public BigDecimal divide(BigDecimal divisor) + throws ArithmeticException, IllegalArgumentException + { + return divide(divisor, scale, ROUND_UNNECESSARY); + } + + /** + * Returns a BigDecimal whose value is the remainder in the quotient + * this / val. This is obtained by + * subtract(divideToIntegralValue(val).multiply(val)). + * @param val the divisor + * @return a BigDecimal whose value is the remainder + * @throws ArithmeticException if val == 0 + * @since 1.5 + */ + public BigDecimal remainder(BigDecimal val) + { + return subtract(divideToIntegralValue(val).multiply(val)); + } + + /** + * Returns a BigDecimal array, the first element of which is the integer part + * of this / val, and the second element of which is the remainder of + * that quotient. + * @param val the divisor + * @return the above described BigDecimal array + * @throws ArithmeticException if val == 0 + * @since 1.5 + */ + public BigDecimal[] divideAndRemainder(BigDecimal val) + { + BigDecimal[] result = new BigDecimal[2]; + result[0] = divideToIntegralValue(val); + result[1] = subtract(result[0].multiply(val)); + return result; + } + + /** + * Returns a BigDecimal whose value is the integer part of the quotient + * this / val. The preferred scale is this.scale - val.scale. + * @param val the divisor + * @return a BigDecimal whose value is the integer part of this / val. + * @throws ArithmeticException if val == 0 + * @since 1.5 + */ + public BigDecimal divideToIntegralValue(BigDecimal val) + { + return divide(val, ROUND_DOWN).floor().setScale(scale - val.scale, ROUND_DOWN); + } + + /** + * Mutates this BigDecimal into one with no fractional part, whose value is + * equal to the largest integer that is <= to this BigDecimal. Note that + * since this method is private it is okay to mutate this BigDecimal. + * @return the BigDecimal obtained through the floor operation on this + * BigDecimal. + */ + private BigDecimal floor() + { + if (scale <= 0) + return this; + String intValStr = intVal.toString(); + intValStr = intValStr.substring(0, intValStr.length() - scale); + intVal = new BigInteger(intValStr).multiply(BigInteger.TEN.pow(scale)); + return this; + } + + public int compareTo (BigDecimal val) + { + if (scale == val.scale) + return intVal.compareTo (val.intVal); + + BigInteger thisParts[] = + intVal.divideAndRemainder (BigInteger.TEN.pow (scale)); + BigInteger valParts[] = + val.intVal.divideAndRemainder (BigInteger.TEN.pow (val.scale)); + + int compare; + if ((compare = thisParts[0].compareTo (valParts[0])) != 0) + return compare; + + // quotients are the same, so compare remainders + + // Add some trailing zeros to the remainder with the smallest scale + if (scale < val.scale) + thisParts[1] = thisParts[1].multiply + (BigInteger.valueOf (10).pow (val.scale - scale)); + else if (scale > val.scale) + valParts[1] = valParts[1].multiply + (BigInteger.valueOf (10).pow (scale - val.scale)); + + // and compare them + return thisParts[1].compareTo (valParts[1]); + } + + public boolean equals (Object o) + { + return (o instanceof BigDecimal + && scale == ((BigDecimal) o).scale + && compareTo ((BigDecimal) o) == 0); + } + + public int hashCode() + { + return intValue() ^ scale; + } + + public BigDecimal max (BigDecimal val) + { + switch (compareTo (val)) + { + case 1: + return this; + default: + return val; + } + } + + public BigDecimal min (BigDecimal val) + { + switch (compareTo (val)) + { + case -1: + return this; + default: + return val; + } + } + + public BigDecimal movePointLeft (int n) + { + return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n); + } + + public BigDecimal movePointRight (int n) + { + if (n < 0) + return movePointLeft (-n); + + if (scale >= n) + return new BigDecimal (intVal, scale - n); + + return new BigDecimal (intVal.multiply + (BigInteger.TEN.pow (n - scale)), 0); + } + + public int signum () + { + return intVal.signum (); + } + + public int scale () + { + return scale; + } + + public BigInteger unscaledValue() + { + return intVal; + } + + public BigDecimal abs () + { + return new BigDecimal (intVal.abs (), scale); + } + + public BigDecimal negate () + { + return new BigDecimal (intVal.negate (), scale); + } + + /** + * Returns a BigDecimal whose value is found first by negating this via + * the negate() method, then by rounding according to the MathContext mc. + * @param mc the MathContext for rounding + * @return a BigDecimal whose value is approximately (-this) + * @throws ArithmeticException if the value is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal negate(MathContext mc) + { + BigDecimal result = negate(); + if (mc.getPrecision() != 0) + result = result.round(mc); + return result; + } + + /** + * Returns this BigDecimal. This is included for symmetry with the + * method negate(). + * @return this + * @since 1.5 + */ + public BigDecimal plus() + { + return this; + } + + /** + * Returns a BigDecimal whose value is found by rounding <code>this</code> + * according to the MathContext. This is the same as round(MathContext). + * @param mc the MathContext for rounding + * @return a BigDecimal whose value is <code>this</code> before being rounded + * @throws ArithmeticException if the value is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + public BigDecimal plus(MathContext mc) + { + return round(mc); + } + + /** + * Returns a BigDecimal which is this BigDecimal rounded according to the + * MathContext rounding settings. + * @param mc the MathContext that tells us how to round + * @return the rounded BigDecimal + */ + public BigDecimal round(MathContext mc) + { + int mcPrecision = mc.getPrecision(); + int numToChop = precision() - mcPrecision; + // If mc specifies not to chop any digits or if we've already chopped + // enough digits (say by using a MathContext in the constructor for this + // BigDecimal) then just return this. + if (mcPrecision == 0 || numToChop <= 0) + return this; + + // 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.TEN.pow(numToChop)); + BigDecimal rounded = divide(div, scale, mc.getRoundingMode().ordinal()); + rounded.scale -= numToChop; + rounded.precision = mcPrecision; + return rounded; + } + + /** + * Returns the precision of this BigDecimal (the number of digits in the + * unscaled value). The precision of a zero value is 1. + * @return the number of digits in the unscaled value, or 1 if the value + * is zero. + */ + public int precision() + { + if (precision == 0) + { + String s = intVal.toString(); + precision = s.length() - (( s.charAt(0) == '-' ) ? 1 : 0); + } + return precision; + } + + /** + * Returns the String representation of this BigDecimal, using scientific + * notation if necessary. The following steps are taken to generate + * the result: + * + * 1. the BigInteger unscaledValue's toString method is called and if + * <code>scale == 0<code> is returned. + * 2. an <code>int adjExp</code> is created which is equal to the negation + * of <code>scale</code> plus the number of digits in the unscaled value, + * minus one. + * 3. if <code>scale >= 0 && adjExp >= -6</code> then we represent this + * BigDecimal without scientific notation. A decimal is added if the + * scale is positive and zeros are prepended as necessary. + * 4. if scale is negative or adjExp is less than -6 we use scientific + * notation. If the unscaled value has more than one digit, a decimal + * as inserted after the first digit, the character 'E' is appended + * and adjExp is appended. + */ + public String toString() + { + // bigStr is the String representation of the unscaled value. If + // scale is zero we simply return this. + String bigStr = intVal.toString(); + if (scale == 0) + return bigStr; + + boolean negative = (bigStr.charAt(0) == '-'); + int point = bigStr.length() - scale - (negative ? 1 : 0); + + CPStringBuilder val = new CPStringBuilder(); + + if (scale >= 0 && (point - 1) >= -6) + { + // Convert to character form without scientific notation. + if (point <= 0) + { + // Zeros need to be prepended to the StringBuilder. + if (negative) + val.append('-'); + // Prepend a '0' and a '.' and then as many more '0's as necessary. + val.append('0').append('.'); + while (point < 0) + { + val.append('0'); + point++; + } + // Append the unscaled value. + val.append(bigStr.substring(negative ? 1 : 0)); + } + else + { + // No zeros need to be prepended so the String is simply the + // unscaled value with the decimal point inserted. + val.append(bigStr); + val.insert(point + (negative ? 1 : 0), '.'); + } + } + else + { + // We must use scientific notation to represent this BigDecimal. + val.append(bigStr); + // If there is more than one digit in the unscaled value we put a + // decimal after the first digit. + if (bigStr.length() > 1) + val.insert( ( negative ? 2 : 1 ), '.'); + // And then append 'E' and the exponent = (point - 1). + val.append('E'); + if (point - 1 >= 0) + val.append('+'); + val.append( point - 1 ); + } + return val.toString(); + } + + /** + * Returns the String representation of this BigDecimal, using engineering + * notation if necessary. This is similar to toString() but when exponents + * are used the exponent is made to be a multiple of 3 such that the integer + * part is between 1 and 999. + * + * @return a String representation of this BigDecimal in engineering notation + * @since 1.5 + */ + public String toEngineeringString() + { + // bigStr is the String representation of the unscaled value. If + // scale is zero we simply return this. + String bigStr = intVal.toString(); + if (scale == 0) + return bigStr; + + boolean negative = (bigStr.charAt(0) == '-'); + int point = bigStr.length() - scale - (negative ? 1 : 0); + + // This is the adjusted exponent described above. + int adjExp = point - 1; + CPStringBuilder val = new CPStringBuilder(); + + if (scale >= 0 && adjExp >= -6) + { + // Convert to character form without scientific notation. + if (point <= 0) + { + // Zeros need to be prepended to the StringBuilder. + if (negative) + val.append('-'); + // Prepend a '0' and a '.' and then as many more '0's as necessary. + val.append('0').append('.'); + while (point < 0) + { + val.append('0'); + point++; + } + // Append the unscaled value. + val.append(bigStr.substring(negative ? 1 : 0)); + } + else + { + // No zeros need to be prepended so the String is simply the + // unscaled value with the decimal point inserted. + val.append(bigStr); + val.insert(point + (negative ? 1 : 0), '.'); + } + } + else + { + // We must use scientific notation to represent this BigDecimal. + // The exponent must be a multiple of 3 and the integer part + // must be between 1 and 999. + val.append(bigStr); + int zeros = adjExp % 3; + int dot = 1; + if (adjExp > 0) + { + // If the exponent is positive we just move the decimal to the + // right and decrease the exponent until it is a multiple of 3. + dot += zeros; + adjExp -= zeros; + } + else + { + // If the exponent is negative then we move the dot to the right + // and decrease the exponent (increase its magnitude) until + // it is a multiple of 3. Note that this is not adjExp -= zeros + // because the mod operator doesn't give us the distance to the + // correct multiple of 3. (-5 mod 3) is -2 but the distance from + // -5 to the correct multiple of 3 (-6) is 1, not 2. + if (zeros == -2) + { + dot += 1; + adjExp -= 1; + } + else if (zeros == -1) + { + dot += 2; + adjExp -= 2; + } + } + + // Either we have to append zeros because, for example, 1.1E+5 should + // be 110E+3, or we just have to put the decimal in the right place. + if (dot > val.length()) + { + while (dot > val.length()) + val.append('0'); + } + else if (bigStr.length() > dot) + val.insert(dot + (negative ? 1 : 0), '.'); + + // And then append 'E' and the exponent (adjExp). + val.append('E'); + if (adjExp >= 0) + val.append('+'); + val.append(adjExp); + } + return val.toString(); + } + + /** + * Returns a String representation of this BigDecimal without using + * scientific notation. This is how toString() worked for releases 1.4 + * and previous. Zeros may be added to the end of the String. For + * example, an unscaled value of 1234 and a scale of -3 would result in + * the String 1234000, but the toString() method would return + * 1.234E+6. + * @return a String representation of this BigDecimal + * @since 1.5 + */ + public String toPlainString() + { + // If the scale is zero we simply return the String representation of the + // unscaled value. + String bigStr = intVal.toString(); + if (scale == 0) + return bigStr; + + // Remember if we have to put a negative sign at the start. + boolean negative = (bigStr.charAt(0) == '-'); + + int point = bigStr.length() - scale - (negative ? 1 : 0); + + CPStringBuilder sb = new CPStringBuilder(bigStr.length() + 2 + + (point <= 0 ? (-point + 1) : 0)); + if (point <= 0) + { + // We have to prepend zeros and a decimal point. + if (negative) + sb.append('-'); + sb.append('0').append('.'); + while (point < 0) + { + sb.append('0'); + point++; + } + sb.append(bigStr.substring(negative ? 1 : 0)); + } + else if (point < bigStr.length()) + { + // No zeros need to be prepended or appended, just put the decimal + // in the right place. + sb.append(bigStr); + sb.insert(point + (negative ? 1 : 0), '.'); + } + else + { + // We must append zeros instead of using scientific notation. + sb.append(bigStr); + for (int i = bigStr.length(); i < point; i++) + sb.append('0'); + } + return sb.toString(); + } + + /** + * Converts this BigDecimal to a BigInteger. Any fractional part will + * be discarded. + * @return a BigDecimal whose value is equal to floor[this] + */ + public BigInteger toBigInteger () + { + // 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.TEN.pow (scale)); + else if (scale < 0) + return intVal.multiply(BigInteger.TEN.pow(-scale)); + return intVal; + } + + /** + * Converts this BigDecimal into a BigInteger, throwing an + * ArithmeticException if the conversion is not exact. + * @return a BigInteger whose value is equal to the value of this BigDecimal + * @since 1.5 + */ + public BigInteger toBigIntegerExact() + { + if (scale > 0) + { + // If we have to divide, we must check if the result is exact. + BigInteger[] result = + 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.TEN.pow(-scale)); + // If the scale is zero we can simply return intVal. + return intVal; + } + + public int intValue () + { + return toBigInteger ().intValue (); + } + + /** + * Returns a BigDecimal which is numerically equal to this BigDecimal but + * with no trailing zeros in the representation. For example, if this + * BigDecimal has [unscaledValue, scale] = [6313000, 4] this method returns + * a BigDecimal with [unscaledValue, scale] = [6313, 1]. As another + * example, [12400, -2] would become [124, -4]. + * @return a numerically equal BigDecimal with no trailing zeros + */ + public BigDecimal stripTrailingZeros() + { + String intValStr = intVal.toString(); + int newScale = scale; + int pointer = intValStr.length() - 1; + // This loop adjusts pointer which will be used to give us the substring + // of intValStr to use in our new BigDecimal, and also accordingly + // adjusts the scale of our new BigDecimal. + while (intValStr.charAt(pointer) == '0') + { + pointer --; + newScale --; + } + // Create a new BigDecimal with the appropriate substring and then + // set its scale. + BigDecimal result = new BigDecimal(intValStr.substring(0, pointer + 1)); + result.scale = newScale; + return result; + } + + public long longValue () + { + return toBigInteger().longValue(); + } + + public float floatValue() + { + return Float.valueOf(toString()).floatValue(); + } + + public double doubleValue() + { + return Double.valueOf(toString()).doubleValue(); + } + + public BigDecimal setScale (int scale) throws ArithmeticException + { + return setScale (scale, ROUND_UNNECESSARY); + } + + public BigDecimal setScale (int scale, int roundingMode) + throws ArithmeticException, IllegalArgumentException + { + // NOTE: The 1.5 JRE doesn't throw this, ones prior to it do and + // the spec says it should. Nevertheless, if 1.6 doesn't fix this + // we should consider removing it. + if( scale < 0 ) throw new ArithmeticException("Scale parameter < 0."); + return divide (ONE, scale, roundingMode); + } + + /** + * Returns a BigDecimal whose value is the same as this BigDecimal but whose + * representation has a scale of <code>newScale</code>. If the scale is + * reduced then rounding may occur, according to the RoundingMode. + * @param newScale + * @param roundingMode + * @return a BigDecimal whose scale is as given, whose value is + * <code>this</code> with possible rounding + * @throws ArithmeticException if the rounding mode is UNNECESSARY but + * rounding is required + * @since 1.5 + */ + public BigDecimal setScale(int newScale, RoundingMode roundingMode) + { + return setScale(newScale, roundingMode.ordinal()); + } + + /** + * Returns a new BigDecimal constructed from the BigDecimal(String) + * constructor using the Double.toString(double) method to obtain + * the String. + * @param val the double value used in Double.toString(double) + * @return a BigDecimal representation of val + * @throws NumberFormatException if val is NaN or infinite + * @since 1.5 + */ + public static BigDecimal valueOf(double val) + { + if (Double.isInfinite(val) || Double.isNaN(val)) + throw new NumberFormatException("argument cannot be NaN or infinite."); + return new BigDecimal(Double.toString(val)); + } + + /** + * Returns a BigDecimal whose numerical value is the numerical value + * of this BigDecimal multiplied by 10 to the power of <code>n</code>. + * @param n the power of ten + * @return the new BigDecimal + * @since 1.5 + */ + public BigDecimal scaleByPowerOfTen(int n) + { + BigDecimal result = new BigDecimal(intVal, scale - n); + result.precision = precision; + return result; + } + + /** + * Returns a BigDecimal whose value is <code>this</code> to the power of + * <code>n</code>. + * @param n the power + * @return the new BigDecimal + * @since 1.5 + */ + public BigDecimal pow(int n) + { + if (n < 0 || n > 999999999) + throw new ArithmeticException("n must be between 0 and 999999999"); + BigDecimal result = new BigDecimal(intVal.pow(n), scale * n); + return result; + } + + /** + * 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 + * @return the new BigDecimal + */ + public BigDecimal abs(MathContext mc) + { + BigDecimal result = abs(); + result = result.round(mc); + return result; + } + + /** + * Returns the size of a unit in the last place of this BigDecimal. This + * returns a BigDecimal with [unscaledValue, scale] = [1, this.scale()]. + * @return the size of a unit in the last place of <code>this</code>. + * @since 1.5 + */ + public BigDecimal ulp() + { + return new BigDecimal(BigInteger.ONE, scale); + } + + /** + * Converts this BigDecimal to a long value. + * @return the long value + * @throws ArithmeticException if rounding occurs or if overflow occurs + * @since 1.5 + */ + public long longValueExact() + { + // Set scale will throw an exception if rounding occurs. + BigDecimal temp = setScale(0, ROUND_UNNECESSARY); + BigInteger tempVal = temp.intVal; + // Check for overflow. + long result = intVal.longValue(); + if (tempVal.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 1 + || (result < 0 && signum() == 1) || (result > 0 && signum() == -1)) + throw new ArithmeticException("this BigDecimal is too " + + "large to fit into the return type"); + + return intVal.longValue(); + } + + /** + * Converts this BigDecimal into an int by first calling longValueExact + * and then checking that the <code>long</code> returned from that + * method fits into an <code>int</code>. + * @return an int whose value is <code>this</code> + * @throws ArithmeticException if this BigDecimal has a fractional part + * or is too large to fit into an int. + * @since 1.5 + */ + public int intValueExact() + { + long temp = longValueExact(); + int result = (int)temp; + if (result != temp) + throw new ArithmeticException ("this BigDecimal cannot fit into an int"); + return result; + } + + /** + * Converts this BigDecimal into a byte by first calling longValueExact + * and then checking that the <code>long</code> returned from that + * method fits into a <code>byte</code>. + * @return a byte whose value is <code>this</code> + * @throws ArithmeticException if this BigDecimal has a fractional part + * or is too large to fit into a byte. + * @since 1.5 + */ + public byte byteValueExact() + { + long temp = longValueExact(); + byte result = (byte)temp; + if (result != temp) + throw new ArithmeticException ("this BigDecimal cannot fit into a byte"); + return result; + } + + /** + * Converts this BigDecimal into a short by first calling longValueExact + * and then checking that the <code>long</code> returned from that + * method fits into a <code>short</code>. + * @return a short whose value is <code>this</code> + * @throws ArithmeticException if this BigDecimal has a fractional part + * or is too large to fit into a short. + * @since 1.5 + */ + public short shortValueExact() + { + long temp = longValueExact(); + short result = (short)temp; + if (result != temp) + throw new ArithmeticException ("this BigDecimal cannot fit into a short"); + return result; + } +} |