diff options
Diffstat (limited to 'libjava/classpath/java/math/BigDecimal.java')
| -rw-r--r-- | libjava/classpath/java/math/BigDecimal.java | 1559 |
1 files changed, 0 insertions, 1559 deletions
diff --git a/libjava/classpath/java/math/BigDecimal.java b/libjava/classpath/java/math/BigDecimal.java deleted file mode 100644 index 7f4546c..0000000 --- a/libjava/classpath/java/math/BigDecimal.java +++ /dev/null @@ -1,1559 +0,0 @@ -/* 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; - } -} |
