diff options
Diffstat (limited to 'libjava/classpath/java/math')
-rw-r--r-- | libjava/classpath/java/math/BigDecimal.java | 1559 | ||||
-rw-r--r-- | libjava/classpath/java/math/BigInteger.java | 2676 | ||||
-rw-r--r-- | libjava/classpath/java/math/MathContext.java | 198 | ||||
-rw-r--r-- | libjava/classpath/java/math/RoundingMode.java | 89 | ||||
-rw-r--r-- | libjava/classpath/java/math/package.html | 46 |
5 files changed, 4568 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; + } +} diff --git a/libjava/classpath/java/math/BigInteger.java b/libjava/classpath/java/math/BigInteger.java new file mode 100644 index 000000000..953e557a8 --- /dev/null +++ b/libjava/classpath/java/math/BigInteger.java @@ -0,0 +1,2676 @@ +/* java.math.BigInteger -- Arbitary precision integers + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007 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.classpath.Configuration; + +import gnu.java.lang.CPStringBuilder; +import gnu.java.math.GMP; +import gnu.java.math.MPN; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Random; +import java.util.logging.Logger; + +/** + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998) and + * "Applied Cryptography, Second Edition" by Bruce Schneier (Wiley, 1996). + * + * Based primarily on IntNum.java BitOps.java by Per Bothner (per@bothner.com) + * (found in Kawa 1.6.62). + * + * @author Warren Levy (warrenl@cygnus.com) + * @date December 20, 1999. + * @status believed complete and correct. + */ +public class BigInteger extends Number implements Comparable<BigInteger> +{ + private static final Logger log = Logger.getLogger(BigInteger.class.getName()); + + /** All integers are stored in 2's-complement form. + * If words == null, the ival is the value of this BigInteger. + * Otherwise, the first ival elements of words make the value + * of this BigInteger, stored in little-endian order, 2's-complement form. */ + private transient int ival; + private transient int[] words; + + // Serialization fields. + // the first three, although not used in the code, are present for + // compatibility with older RI versions of this class. DO NOT REMOVE. + private int bitCount = -1; + private int bitLength = -1; + private int lowestSetBit = -2; + private byte[] magnitude; + private int signum; + private static final long serialVersionUID = -8287574255936472291L; + + + /** We pre-allocate integers in the range minFixNum..maxFixNum. + * Note that we must at least preallocate 0, 1, and 10. */ + private static final int minFixNum = -100; + private static final int maxFixNum = 1024; + private static final int numFixNum = maxFixNum-minFixNum+1; + private static final BigInteger[] smallFixNums; + + /** The alter-ego GMP instance for this. */ + private transient GMP mpz; + + private static final boolean USING_NATIVE = Configuration.WANT_NATIVE_BIG_INTEGER + && initializeLibrary(); + + static + { + if (USING_NATIVE) + { + smallFixNums = null; + ZERO = valueOf(0L); + ONE = valueOf(1L); + TEN = valueOf(10L); + } + else + { + smallFixNums = new BigInteger[numFixNum]; + for (int i = numFixNum; --i >= 0; ) + smallFixNums[i] = new BigInteger(i + minFixNum); + + ZERO = smallFixNums[-minFixNum]; + ONE = smallFixNums[1 - minFixNum]; + TEN = smallFixNums[10 - minFixNum]; + } + } + + /** + * The constant zero as a BigInteger. + * @since 1.2 + */ + public static final BigInteger ZERO; + + /** + * The constant one as a BigInteger. + * @since 1.2 + */ + public static final BigInteger ONE; + + /** + * The constant ten as a BigInteger. + * @since 1.5 + */ + public static final BigInteger TEN; + + /* Rounding modes: */ + private static final int FLOOR = 1; + private static final int CEILING = 2; + private static final int TRUNCATE = 3; + private static final int ROUND = 4; + + /** When checking the probability of primes, it is most efficient to + * first check the factoring of small primes, so we'll use this array. + */ + private static final int[] primes = + { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, + 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, + 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251 }; + + /** HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Table 4.4. */ + private static final int[] k = + {100,150,200,250,300,350,400,500,600,800,1250, Integer.MAX_VALUE}; + private static final int[] t = + { 27, 18, 15, 12, 9, 8, 7, 6, 5, 4, 3, 2}; + + private BigInteger() + { + super(); + + if (USING_NATIVE) + mpz = new GMP(); + } + + /* Create a new (non-shared) BigInteger, and initialize to an int. */ + private BigInteger(int value) + { + super(); + + ival = value; + } + + public BigInteger(String s, int radix) + { + this(); + + int len = s.length(); + int i, digit; + boolean negative; + byte[] bytes; + char ch = s.charAt(0); + if (ch == '-') + { + negative = true; + i = 1; + bytes = new byte[len - 1]; + } + else + { + negative = false; + i = 0; + bytes = new byte[len]; + } + int byte_len = 0; + for ( ; i < len; i++) + { + ch = s.charAt(i); + digit = Character.digit(ch, radix); + if (digit < 0) + throw new NumberFormatException("Invalid character at position #" + i); + bytes[byte_len++] = (byte) digit; + } + + if (USING_NATIVE) + { + bytes = null; + if (mpz.fromString(s, radix) != 0) + throw new NumberFormatException("String \"" + s + + "\" is NOT a valid number in base " + + radix); + } + else + { + BigInteger result; + // Testing (len < MPN.chars_per_word(radix)) would be more accurate, + // but slightly more expensive, for little practical gain. + if (len <= 15 && radix <= 16) + result = valueOf(Long.parseLong(s, radix)); + else + result = valueOf(bytes, byte_len, negative, radix); + + this.ival = result.ival; + this.words = result.words; + } + } + + public BigInteger(String val) + { + this(val, 10); + } + + /* Create a new (non-shared) BigInteger, and initialize from a byte array. */ + public BigInteger(byte[] val) + { + this(); + + if (val == null || val.length < 1) + throw new NumberFormatException(); + + if (USING_NATIVE) + mpz.fromByteArray(val); + else + { + words = byteArrayToIntArray(val, val[0] < 0 ? -1 : 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + } + } + + public BigInteger(int signum, byte[] magnitude) + { + this(); + + if (magnitude == null || signum > 1 || signum < -1) + throw new NumberFormatException(); + + if (signum == 0) + { + int i; + for (i = magnitude.length - 1; i >= 0 && magnitude[i] == 0; --i) + ; + if (i >= 0) + throw new NumberFormatException(); + return; + } + + if (USING_NATIVE) + mpz.fromSignedMagnitude(magnitude, signum == -1); + else + { + // Magnitude is always positive, so don't ever pass a sign of -1. + words = byteArrayToIntArray(magnitude, 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + + if (signum < 0) + setNegative(); + } + } + + public BigInteger(int numBits, Random rnd) + { + this(); + + if (numBits < 0) + throw new IllegalArgumentException(); + + init(numBits, rnd); + } + + private void init(int numBits, Random rnd) + { + if (USING_NATIVE) + { + int length = (numBits + 7) / 8; + byte[] magnitude = new byte[length]; + rnd.nextBytes(magnitude); + int discardedBitCount = numBits % 8; + if (discardedBitCount != 0) + { + discardedBitCount = 8 - discardedBitCount; + magnitude[0] = (byte)((magnitude[0] & 0xFF) >>> discardedBitCount); + } + mpz.fromSignedMagnitude(magnitude, false); + magnitude = null; + return; + } + + int highbits = numBits & 31; + // minimum number of bytes to store the above number of bits + int highBitByteCount = (highbits + 7) / 8; + // number of bits to discard from the last byte + int discardedBitCount = highbits % 8; + if (discardedBitCount != 0) + discardedBitCount = 8 - discardedBitCount; + byte[] highBitBytes = new byte[highBitByteCount]; + if (highbits > 0) + { + rnd.nextBytes(highBitBytes); + highbits = (highBitBytes[highBitByteCount - 1] & 0xFF) >>> discardedBitCount; + for (int i = highBitByteCount - 2; i >= 0; i--) + highbits = (highbits << 8) | (highBitBytes[i] & 0xFF); + } + int nwords = numBits / 32; + + while (highbits == 0 && nwords > 0) + { + highbits = rnd.nextInt(); + --nwords; + } + if (nwords == 0 && highbits >= 0) + { + ival = highbits; + } + else + { + ival = highbits < 0 ? nwords + 2 : nwords + 1; + words = new int[ival]; + words[nwords] = highbits; + while (--nwords >= 0) + words[nwords] = rnd.nextInt(); + } + } + + public BigInteger(int bitLength, int certainty, Random rnd) + { + this(); + + BigInteger result = new BigInteger(); + while (true) + { + result.init(bitLength, rnd); + result = result.setBit(bitLength - 1); + if (result.isProbablePrime(certainty)) + break; + } + + if (USING_NATIVE) + mpz.fromBI(result.mpz); + else + { + this.ival = result.ival; + this.words = result.words; + } + } + + /** + * Return a BigInteger that is bitLength bits long with a + * probability < 2^-100 of being composite. + * + * @param bitLength length in bits of resulting number + * @param rnd random number generator to use + * @throws ArithmeticException if bitLength < 2 + * @since 1.4 + */ + public static BigInteger probablePrime(int bitLength, Random rnd) + { + if (bitLength < 2) + throw new ArithmeticException(); + + return new BigInteger(bitLength, 100, rnd); + } + + /** Return a (possibly-shared) BigInteger with a given long value. */ + public static BigInteger valueOf(long val) + { + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + result.mpz.fromLong(val); + return result; + } + + if (val >= minFixNum && val <= maxFixNum) + return smallFixNums[(int) val - minFixNum]; + int i = (int) val; + if ((long) i == val) + return new BigInteger(i); + BigInteger result = alloc(2); + result.ival = 2; + result.words[0] = i; + result.words[1] = (int)(val >> 32); + return result; + } + + /** + * @return <code>true</code> if the GMP-based native implementation library + * was successfully loaded. Returns <code>false</code> otherwise. + */ + private static boolean initializeLibrary() + { + boolean result; + try + { + System.loadLibrary("javamath"); + GMP.natInitializeLibrary(); + result = true; + } + catch (Throwable x) + { + result = false; + if (Configuration.DEBUG) + { + log.info("Unable to use native BigInteger: " + x); + log.info("Will use a pure Java implementation instead"); + } + } + return result; + } + + /** Make a canonicalized BigInteger from an array of words. + * The array may be reused (without copying). */ + private static BigInteger make(int[] words, int len) + { + if (words == null) + return valueOf(len); + len = BigInteger.wordsNeeded(words, len); + if (len <= 1) + return len == 0 ? ZERO : valueOf(words[0]); + BigInteger num = new BigInteger(); + num.words = words; + num.ival = len; + return num; + } + + /** Convert a big-endian byte array to a little-endian array of words. */ + private static int[] byteArrayToIntArray(byte[] bytes, int sign) + { + // Determine number of words needed. + int[] words = new int[bytes.length/4 + 1]; + int nwords = words.length; + + // Create a int out of modulo 4 high order bytes. + int bptr = 0; + int word = sign; + for (int i = bytes.length % 4; i > 0; --i, bptr++) + word = (word << 8) | (bytes[bptr] & 0xff); + words[--nwords] = word; + + // Elements remaining in byte[] are a multiple of 4. + while (nwords > 0) + words[--nwords] = bytes[bptr++] << 24 | + (bytes[bptr++] & 0xff) << 16 | + (bytes[bptr++] & 0xff) << 8 | + (bytes[bptr++] & 0xff); + return words; + } + + /** Allocate a new non-shared BigInteger. + * @param nwords number of words to allocate + */ + private static BigInteger alloc(int nwords) + { + BigInteger result = new BigInteger(); + if (nwords > 1) + result.words = new int[nwords]; + return result; + } + + /** Change words.length to nwords. + * We allow words.length to be upto nwords+2 without reallocating. + */ + private void realloc(int nwords) + { + if (nwords == 0) + { + if (words != null) + { + if (ival > 0) + ival = words[0]; + words = null; + } + } + else if (words == null + || words.length < nwords + || words.length > nwords + 2) + { + int[] new_words = new int [nwords]; + if (words == null) + { + new_words[0] = ival; + ival = 1; + } + else + { + if (nwords < ival) + ival = nwords; + System.arraycopy(words, 0, new_words, 0, ival); + } + words = new_words; + } + } + + private boolean isNegative() + { + return (words == null ? ival : words[ival - 1]) < 0; + } + + public int signum() + { + if (USING_NATIVE) + return mpz.compare(ZERO.mpz); + + if (ival == 0 && words == null) + return 0; + int top = words == null ? ival : words[ival-1]; + return top < 0 ? -1 : 1; + } + + private static int compareTo(BigInteger x, BigInteger y) + { + if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + return x.mpz.compare(y.mpz); + } + + if (x.words == null && y.words == null) + return x.ival < y.ival ? -1 : x.ival > y.ival ? 1 : 0; + boolean x_negative = x.isNegative(); + boolean y_negative = y.isNegative(); + if (x_negative != y_negative) + return x_negative ? -1 : 1; + int x_len = x.words == null ? 1 : x.ival; + int y_len = y.words == null ? 1 : y.ival; + if (x_len != y_len) + return (x_len > y_len) != x_negative ? 1 : -1; + return MPN.cmp(x.words, y.words, x_len); + } + + /** @since 1.2 */ + public int compareTo(BigInteger val) + { + return compareTo(this, val); + } + + public BigInteger min(BigInteger val) + { + return compareTo(this, val) < 0 ? this : val; + } + + public BigInteger max(BigInteger val) + { + return compareTo(this, val) > 0 ? this : val; + } + + private boolean isZero() + { + return words == null && ival == 0; + } + + private boolean isOne() + { + return words == null && ival == 1; + } + + /** Calculate how many words are significant in words[0:len-1]. + * Returns the least value x such that x>0 && words[0:x-1]==words[0:len-1], + * when words is viewed as a 2's complement integer. + */ + private static int wordsNeeded(int[] words, int len) + { + int i = len; + if (i > 0) + { + int word = words[--i]; + if (word == -1) + { + while (i > 0 && (word = words[i - 1]) < 0) + { + i--; + if (word != -1) break; + } + } + else + { + while (word == 0 && i > 0 && (word = words[i - 1]) >= 0) i--; + } + } + return i + 1; + } + + private BigInteger canonicalize() + { + if (words != null + && (ival = BigInteger.wordsNeeded(words, ival)) <= 1) + { + if (ival == 1) + ival = words[0]; + words = null; + } + if (words == null && ival >= minFixNum && ival <= maxFixNum) + return smallFixNums[ival - minFixNum]; + return this; + } + + /** Add two ints, yielding a BigInteger. */ + private static BigInteger add(int x, int y) + { + return valueOf((long) x + (long) y); + } + + /** Add a BigInteger and an int, yielding a new BigInteger. */ + private static BigInteger add(BigInteger x, int y) + { + if (x.words == null) + return BigInteger.add(x.ival, y); + BigInteger result = new BigInteger(0); + result.setAdd(x, y); + return result.canonicalize(); + } + + /** Set this to the sum of x and y. + * OK if x==this. */ + private void setAdd(BigInteger x, int y) + { + if (x.words == null) + { + set((long) x.ival + (long) y); + return; + } + int len = x.ival; + realloc(len + 1); + long carry = y; + for (int i = 0; i < len; i++) + { + carry += ((long) x.words[i] & 0xffffffffL); + words[i] = (int) carry; + carry >>= 32; + } + if (x.words[len - 1] < 0) + carry--; + words[len] = (int) carry; + ival = wordsNeeded(words, len + 1); + } + + /** Destructively add an int to this. */ + private void setAdd(int y) + { + setAdd(this, y); + } + + /** Destructively set the value of this to a long. */ + private void set(long y) + { + int i = (int) y; + if ((long) i == y) + { + ival = i; + words = null; + } + else + { + realloc(2); + words[0] = i; + words[1] = (int) (y >> 32); + ival = 2; + } + } + + /** Destructively set the value of this to the given words. + * The words array is reused, not copied. */ + private void set(int[] words, int length) + { + this.ival = length; + this.words = words; + } + + /** Destructively set the value of this to that of y. */ + private void set(BigInteger y) + { + if (y.words == null) + set(y.ival); + else if (this != y) + { + realloc(y.ival); + System.arraycopy(y.words, 0, words, 0, y.ival); + ival = y.ival; + } + } + + /** Add two BigIntegers, yielding their sum as another BigInteger. */ + private static BigInteger add(BigInteger x, BigInteger y, int k) + { + if (x.words == null && y.words == null) + return valueOf((long) k * (long) y.ival + (long) x.ival); + if (k != 1) + { + if (k == -1) + y = BigInteger.neg(y); + else + y = BigInteger.times(y, valueOf(k)); + } + if (x.words == null) + return BigInteger.add(y, x.ival); + if (y.words == null) + return BigInteger.add(x, y.ival); + // Both are big + if (y.ival > x.ival) + { // Swap so x is longer then y. + BigInteger tmp = x; x = y; y = tmp; + } + BigInteger result = alloc(x.ival + 1); + int i = y.ival; + long carry = MPN.add_n(result.words, x.words, y.words, i); + long y_ext = y.words[i - 1] < 0 ? 0xffffffffL : 0; + for (; i < x.ival; i++) + { + carry += ((long) x.words[i] & 0xffffffffL) + y_ext; + result.words[i] = (int) carry; + carry >>>= 32; + } + if (x.words[i - 1] < 0) + y_ext--; + result.words[i] = (int) (carry + y_ext); + result.ival = i+1; + return result.canonicalize(); + } + + public BigInteger add(BigInteger val) + { + if (USING_NATIVE) + { + int dummy = val.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.add(val.mpz, result.mpz); + return result; + } + + return add(this, val, 1); + } + + public BigInteger subtract(BigInteger val) + { + if (USING_NATIVE) + { + int dummy = val.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.subtract(val.mpz, result.mpz); + return result; + } + + return add(this, val, -1); + } + + private static BigInteger times(BigInteger x, int y) + { + if (y == 0) + return ZERO; + if (y == 1) + return x; + int[] xwords = x.words; + int xlen = x.ival; + if (xwords == null) + return valueOf((long) xlen * (long) y); + boolean negative; + BigInteger result = BigInteger.alloc(xlen + 1); + if (xwords[xlen - 1] < 0) + { + negative = true; + negate(result.words, xwords, xlen); + xwords = result.words; + } + else + negative = false; + if (y < 0) + { + negative = !negative; + y = -y; + } + result.words[xlen] = MPN.mul_1(result.words, xwords, xlen, y); + result.ival = xlen + 1; + if (negative) + result.setNegative(); + return result.canonicalize(); + } + + private static BigInteger times(BigInteger x, BigInteger y) + { + if (y.words == null) + return times(x, y.ival); + if (x.words == null) + return times(y, x.ival); + boolean negative = false; + int[] xwords; + int[] ywords; + int xlen = x.ival; + int ylen = y.ival; + if (x.isNegative()) + { + negative = true; + xwords = new int[xlen]; + negate(xwords, x.words, xlen); + } + else + { + negative = false; + xwords = x.words; + } + if (y.isNegative()) + { + negative = !negative; + ywords = new int[ylen]; + negate(ywords, y.words, ylen); + } + else + ywords = y.words; + // Swap if x is shorter then y. + if (xlen < ylen) + { + int[] twords = xwords; xwords = ywords; ywords = twords; + int tlen = xlen; xlen = ylen; ylen = tlen; + } + BigInteger result = BigInteger.alloc(xlen+ylen); + MPN.mul(result.words, xwords, xlen, ywords, ylen); + result.ival = xlen+ylen; + if (negative) + result.setNegative(); + return result.canonicalize(); + } + + public BigInteger multiply(BigInteger y) + { + if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.multiply(y.mpz, result.mpz); + return result; + } + + return times(this, y); + } + + private static void divide(long x, long y, + BigInteger quotient, BigInteger remainder, + int rounding_mode) + { + boolean xNegative, yNegative; + if (x < 0) + { + xNegative = true; + if (x == Long.MIN_VALUE) + { + divide(valueOf(x), valueOf(y), + quotient, remainder, rounding_mode); + return; + } + x = -x; + } + else + xNegative = false; + + if (y < 0) + { + yNegative = true; + if (y == Long.MIN_VALUE) + { + if (rounding_mode == TRUNCATE) + { // x != Long.Min_VALUE implies abs(x) < abs(y) + if (quotient != null) + quotient.set(0); + if (remainder != null) + remainder.set(x); + } + else + divide(valueOf(x), valueOf(y), + quotient, remainder, rounding_mode); + return; + } + y = -y; + } + else + yNegative = false; + + long q = x / y; + long r = x % y; + boolean qNegative = xNegative ^ yNegative; + + boolean add_one = false; + if (r != 0) + { + switch (rounding_mode) + { + case TRUNCATE: + break; + case CEILING: + case FLOOR: + if (qNegative == (rounding_mode == FLOOR)) + add_one = true; + break; + case ROUND: + add_one = r > ((y - (q & 1)) >> 1); + break; + } + } + if (quotient != null) + { + if (add_one) + q++; + if (qNegative) + q = -q; + quotient.set(q); + } + if (remainder != null) + { + // The remainder is by definition: X-Q*Y + if (add_one) + { + // Subtract the remainder from Y. + r = y - r; + // In this case, abs(Q*Y) > abs(X). + // So sign(remainder) = -sign(X). + xNegative = ! xNegative; + } + else + { + // If !add_one, then: abs(Q*Y) <= abs(X). + // So sign(remainder) = sign(X). + } + if (xNegative) + r = -r; + remainder.set(r); + } + } + + /** Divide two integers, yielding quotient and remainder. + * @param x the numerator in the division + * @param y the denominator in the division + * @param quotient is set to the quotient of the result (iff quotient!=null) + * @param remainder is set to the remainder of the result + * (iff remainder!=null) + * @param rounding_mode one of FLOOR, CEILING, TRUNCATE, or ROUND. + */ + private static void divide(BigInteger x, BigInteger y, + BigInteger quotient, BigInteger remainder, + int rounding_mode) + { + if ((x.words == null || x.ival <= 2) + && (y.words == null || y.ival <= 2)) + { + long x_l = x.longValue(); + long y_l = y.longValue(); + if (x_l != Long.MIN_VALUE && y_l != Long.MIN_VALUE) + { + divide(x_l, y_l, quotient, remainder, rounding_mode); + return; + } + } + + boolean xNegative = x.isNegative(); + boolean yNegative = y.isNegative(); + boolean qNegative = xNegative ^ yNegative; + + int ylen = y.words == null ? 1 : y.ival; + int[] ywords = new int[ylen]; + y.getAbsolute(ywords); + while (ylen > 1 && ywords[ylen - 1] == 0) ylen--; + + int xlen = x.words == null ? 1 : x.ival; + int[] xwords = new int[xlen+2]; + x.getAbsolute(xwords); + while (xlen > 1 && xwords[xlen-1] == 0) xlen--; + + int qlen, rlen; + + int cmpval = MPN.cmp(xwords, xlen, ywords, ylen); + if (cmpval < 0) // abs(x) < abs(y) + { // quotient = 0; remainder = num. + int[] rwords = xwords; xwords = ywords; ywords = rwords; + rlen = xlen; qlen = 1; xwords[0] = 0; + } + else if (cmpval == 0) // abs(x) == abs(y) + { + xwords[0] = 1; qlen = 1; // quotient = 1 + ywords[0] = 0; rlen = 1; // remainder = 0; + } + else if (ylen == 1) + { + qlen = xlen; + // Need to leave room for a word of leading zeros if dividing by 1 + // and the dividend has the high bit set. It might be safe to + // increment qlen in all cases, but it certainly is only necessary + // in the following case. + if (ywords[0] == 1 && xwords[xlen-1] < 0) + qlen++; + rlen = 1; + ywords[0] = MPN.divmod_1(xwords, xwords, xlen, ywords[0]); + } + else // abs(x) > abs(y) + { + // Normalize the denominator, i.e. make its most significant bit set by + // shifting it normalization_steps bits to the left. Also shift the + // numerator the same number of steps (to keep the quotient the same!). + + int nshift = MPN.count_leading_zeros(ywords[ylen - 1]); + if (nshift != 0) + { + // Shift up the denominator setting the most significant bit of + // the most significant word. + MPN.lshift(ywords, 0, ywords, ylen, nshift); + + // Shift up the numerator, possibly introducing a new most + // significant word. + int x_high = MPN.lshift(xwords, 0, xwords, xlen, nshift); + xwords[xlen++] = x_high; + } + + if (xlen == ylen) + xwords[xlen++] = 0; + MPN.divide(xwords, xlen, ywords, ylen); + rlen = ylen; + MPN.rshift0 (ywords, xwords, 0, rlen, nshift); + + qlen = xlen + 1 - ylen; + if (quotient != null) + { + for (int i = 0; i < qlen; i++) + xwords[i] = xwords[i+ylen]; + } + } + + if (ywords[rlen-1] < 0) + { + ywords[rlen] = 0; + rlen++; + } + + // Now the quotient is in xwords, and the remainder is in ywords. + + boolean add_one = false; + if (rlen > 1 || ywords[0] != 0) + { // Non-zero remainder i.e. in-exact quotient. + switch (rounding_mode) + { + case TRUNCATE: + break; + case CEILING: + case FLOOR: + if (qNegative == (rounding_mode == FLOOR)) + add_one = true; + break; + case ROUND: + // int cmp = compareTo(remainder<<1, abs(y)); + BigInteger tmp = remainder == null ? new BigInteger() : remainder; + tmp.set(ywords, rlen); + tmp = shift(tmp, 1); + if (yNegative) + tmp.setNegative(); + int cmp = compareTo(tmp, y); + // Now cmp == compareTo(sign(y)*(remainder<<1), y) + if (yNegative) + cmp = -cmp; + add_one = (cmp == 1) || (cmp == 0 && (xwords[0]&1) != 0); + } + } + if (quotient != null) + { + quotient.set(xwords, qlen); + if (qNegative) + { + if (add_one) // -(quotient + 1) == ~(quotient) + quotient.setInvert(); + else + quotient.setNegative(); + } + else if (add_one) + quotient.setAdd(1); + } + if (remainder != null) + { + // The remainder is by definition: X-Q*Y + remainder.set(ywords, rlen); + if (add_one) + { + // Subtract the remainder from Y: + // abs(R) = abs(Y) - abs(orig_rem) = -(abs(orig_rem) - abs(Y)). + BigInteger tmp; + if (y.words == null) + { + tmp = remainder; + tmp.set(yNegative ? ywords[0] + y.ival : ywords[0] - y.ival); + } + else + tmp = BigInteger.add(remainder, y, yNegative ? 1 : -1); + // Now tmp <= 0. + // In this case, abs(Q) = 1 + floor(abs(X)/abs(Y)). + // Hence, abs(Q*Y) > abs(X). + // So sign(remainder) = -sign(X). + if (xNegative) + remainder.setNegative(tmp); + else + remainder.set(tmp); + } + else + { + // If !add_one, then: abs(Q*Y) <= abs(X). + // So sign(remainder) = sign(X). + if (xNegative) + remainder.setNegative(); + } + } + } + + public BigInteger divide(BigInteger val) + { + if (USING_NATIVE) + { + if (val.compareTo(ZERO) == 0) + throw new ArithmeticException("divisor is zero"); + + BigInteger result = new BigInteger(); + mpz.quotient(val.mpz, result.mpz); + return result; + } + + if (val.isZero()) + throw new ArithmeticException("divisor is zero"); + + BigInteger quot = new BigInteger(); + divide(this, val, quot, null, TRUNCATE); + return quot.canonicalize(); + } + + public BigInteger remainder(BigInteger val) + { + if (USING_NATIVE) + { + if (val.compareTo(ZERO) == 0) + throw new ArithmeticException("divisor is zero"); + + BigInteger result = new BigInteger(); + mpz.remainder(val.mpz, result.mpz); + return result; + } + + if (val.isZero()) + throw new ArithmeticException("divisor is zero"); + + BigInteger rem = new BigInteger(); + divide(this, val, null, rem, TRUNCATE); + return rem.canonicalize(); + } + + public BigInteger[] divideAndRemainder(BigInteger val) + { + if (USING_NATIVE) + { + if (val.compareTo(ZERO) == 0) + throw new ArithmeticException("divisor is zero"); + + BigInteger q = new BigInteger(); + BigInteger r = new BigInteger(); + mpz.quotientAndRemainder(val.mpz, q.mpz, r.mpz); + return new BigInteger[] { q, r }; + } + + if (val.isZero()) + throw new ArithmeticException("divisor is zero"); + + BigInteger[] result = new BigInteger[2]; + result[0] = new BigInteger(); + result[1] = new BigInteger(); + divide(this, val, result[0], result[1], TRUNCATE); + result[0].canonicalize(); + result[1].canonicalize(); + return result; + } + + public BigInteger mod(BigInteger m) + { + if (USING_NATIVE) + { + int dummy = m.signum; // force NPE check + if (m.compareTo(ZERO) < 1) + throw new ArithmeticException("non-positive modulus"); + + BigInteger result = new BigInteger(); + mpz.modulo(m.mpz, result.mpz); + return result; + } + + if (m.isNegative() || m.isZero()) + throw new ArithmeticException("non-positive modulus"); + + BigInteger rem = new BigInteger(); + divide(this, m, null, rem, FLOOR); + return rem.canonicalize(); + } + + /** Calculate the integral power of a BigInteger. + * @param exponent the exponent (must be non-negative) + */ + public BigInteger pow(int exponent) + { + if (exponent <= 0) + { + if (exponent == 0) + return ONE; + throw new ArithmeticException("negative exponent"); + } + + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.pow(exponent, result.mpz); + return result; + } + + if (isZero()) + return this; + int plen = words == null ? 1 : ival; // Length of pow2. + int blen = ((bitLength() * exponent) >> 5) + 2 * plen; + boolean negative = isNegative() && (exponent & 1) != 0; + int[] pow2 = new int [blen]; + int[] rwords = new int [blen]; + int[] work = new int [blen]; + getAbsolute(pow2); // pow2 = abs(this); + int rlen = 1; + rwords[0] = 1; // rwords = 1; + for (;;) // for (i = 0; ; i++) + { + // pow2 == this**(2**i) + // prod = this**(sum(j=0..i-1, (exponent>>j)&1)) + if ((exponent & 1) != 0) + { // r *= pow2 + MPN.mul(work, pow2, plen, rwords, rlen); + int[] temp = work; work = rwords; rwords = temp; + rlen += plen; + while (rwords[rlen - 1] == 0) rlen--; + } + exponent >>= 1; + if (exponent == 0) + break; + // pow2 *= pow2; + MPN.mul(work, pow2, plen, pow2, plen); + int[] temp = work; work = pow2; pow2 = temp; // swap to avoid a copy + plen *= 2; + while (pow2[plen - 1] == 0) plen--; + } + if (rwords[rlen - 1] < 0) + rlen++; + if (negative) + negate(rwords, rwords, rlen); + return BigInteger.make(rwords, rlen); + } + + private static int[] euclidInv(int a, int b, int prevDiv) + { + if (b == 0) + throw new ArithmeticException("not invertible"); + + if (b == 1) + // Success: values are indeed invertible! + // Bottom of the recursion reached; start unwinding. + return new int[] { -prevDiv, 1 }; + + int[] xy = euclidInv(b, a % b, a / b); // Recursion happens here. + a = xy[0]; // use our local copy of 'a' as a work var + xy[0] = a * -prevDiv + xy[1]; + xy[1] = a; + return xy; + } + + private static void euclidInv(BigInteger a, BigInteger b, + BigInteger prevDiv, BigInteger[] xy) + { + if (b.isZero()) + throw new ArithmeticException("not invertible"); + + if (b.isOne()) + { + // Success: values are indeed invertible! + // Bottom of the recursion reached; start unwinding. + xy[0] = neg(prevDiv); + xy[1] = ONE; + return; + } + + // Recursion happens in the following conditional! + + // If a just contains an int, then use integer math for the rest. + if (a.words == null) + { + int[] xyInt = euclidInv(b.ival, a.ival % b.ival, a.ival / b.ival); + xy[0] = new BigInteger(xyInt[0]); + xy[1] = new BigInteger(xyInt[1]); + } + else + { + BigInteger rem = new BigInteger(); + BigInteger quot = new BigInteger(); + divide(a, b, quot, rem, FLOOR); + // quot and rem may not be in canonical form. ensure + rem.canonicalize(); + quot.canonicalize(); + euclidInv(b, rem, quot, xy); + } + + BigInteger t = xy[0]; + xy[0] = add(xy[1], times(t, prevDiv), -1); + xy[1] = t; + } + + public BigInteger modInverse(BigInteger y) + { + if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + if (mpz.compare(ZERO.mpz) < 1) + throw new ArithmeticException("non-positive modulo"); + + BigInteger result = new BigInteger(); + mpz.modInverse(y.mpz, result.mpz); + return result; + } + + if (y.isNegative() || y.isZero()) + throw new ArithmeticException("non-positive modulo"); + + // Degenerate cases. + if (y.isOne()) + return ZERO; + if (isOne()) + return ONE; + + // Use Euclid's algorithm as in gcd() but do this recursively + // rather than in a loop so we can use the intermediate results as we + // unwind from the recursion. + // Used http://www.math.nmsu.edu/~crypto/EuclideanAlgo.html as reference. + BigInteger result = new BigInteger(); + boolean swapped = false; + + if (y.words == null) + { + // The result is guaranteed to be less than the modulus, y (which is + // an int), so simplify this by working with the int result of this + // modulo y. Also, if this is negative, make it positive via modulo + // math. Note that BigInteger.mod() must be used even if this is + // already an int as the % operator would provide a negative result if + // this is negative, BigInteger.mod() never returns negative values. + int xval = (words != null || isNegative()) ? mod(y).ival : ival; + int yval = y.ival; + + // Swap values so x > y. + if (yval > xval) + { + int tmp = xval; xval = yval; yval = tmp; + swapped = true; + } + // Normally, the result is in the 2nd element of the array, but + // if originally x < y, then x and y were swapped and the result + // is in the 1st element of the array. + result.ival = + euclidInv(yval, xval % yval, xval / yval)[swapped ? 0 : 1]; + + // Result can't be negative, so make it positive by adding the + // original modulus, y.ival (not the possibly "swapped" yval). + if (result.ival < 0) + result.ival += y.ival; + } + else + { + // As above, force this to be a positive value via modulo math. + BigInteger x = isNegative() ? this.mod(y) : this; + + // Swap values so x > y. + if (x.compareTo(y) < 0) + { + result = x; x = y; y = result; // use 'result' as a work var + swapped = true; + } + // As above (for ints), result will be in the 2nd element unless + // the original x and y were swapped. + BigInteger rem = new BigInteger(); + BigInteger quot = new BigInteger(); + divide(x, y, quot, rem, FLOOR); + // quot and rem may not be in canonical form. ensure + rem.canonicalize(); + quot.canonicalize(); + BigInteger[] xy = new BigInteger[2]; + euclidInv(y, rem, quot, xy); + result = swapped ? xy[0] : xy[1]; + + // Result can't be negative, so make it positive by adding the + // original modulus, y (which is now x if they were swapped). + if (result.isNegative()) + result = add(result, swapped ? x : y, 1); + } + + return result; + } + + public BigInteger modPow(BigInteger exponent, BigInteger m) + { + if (USING_NATIVE) + { + int dummy = exponent.signum; // force NPE check + if (m.mpz.compare(ZERO.mpz) < 1) + throw new ArithmeticException("non-positive modulo"); + + BigInteger result = new BigInteger(); + mpz.modPow(exponent.mpz, m.mpz, result.mpz); + return result; + } + + if (m.isNegative() || m.isZero()) + throw new ArithmeticException("non-positive modulo"); + + if (exponent.isNegative()) + return modInverse(m).modPow(exponent.negate(), m); + if (exponent.isOne()) + return mod(m); + + // To do this naively by first raising this to the power of exponent + // and then performing modulo m would be extremely expensive, especially + // for very large numbers. The solution is found in Number Theory + // where a combination of partial powers and moduli can be done easily. + // + // We'll use the algorithm for Additive Chaining which can be found on + // p. 244 of "Applied Cryptography, Second Edition" by Bruce Schneier. + BigInteger s = ONE; + BigInteger t = this; + BigInteger u = exponent; + + while (!u.isZero()) + { + if (u.and(ONE).isOne()) + s = times(s, t).mod(m); + u = u.shiftRight(1); + t = times(t, t).mod(m); + } + + return s; + } + + /** Calculate Greatest Common Divisor for non-negative ints. */ + private static int gcd(int a, int b) + { + // Euclid's algorithm, copied from libg++. + int tmp; + if (b > a) + { + tmp = a; a = b; b = tmp; + } + for(;;) + { + if (b == 0) + return a; + if (b == 1) + return b; + tmp = b; + b = a % b; + a = tmp; + } + } + + public BigInteger gcd(BigInteger y) + { + if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.gcd(y.mpz, result.mpz); + return result; + } + + int xval = ival; + int yval = y.ival; + if (words == null) + { + if (xval == 0) + return abs(y); + if (y.words == null + && xval != Integer.MIN_VALUE && yval != Integer.MIN_VALUE) + { + if (xval < 0) + xval = -xval; + if (yval < 0) + yval = -yval; + return valueOf(gcd(xval, yval)); + } + xval = 1; + } + if (y.words == null) + { + if (yval == 0) + return abs(this); + yval = 1; + } + int len = (xval > yval ? xval : yval) + 1; + int[] xwords = new int[len]; + int[] ywords = new int[len]; + getAbsolute(xwords); + y.getAbsolute(ywords); + len = MPN.gcd(xwords, ywords, len); + BigInteger result = new BigInteger(0); + result.ival = len; + result.words = xwords; + return result.canonicalize(); + } + + /** + * <p>Returns <code>true</code> if this BigInteger is probably prime, + * <code>false</code> if it's definitely composite. If <code>certainty</code> + * is <code><= 0</code>, <code>true</code> is returned.</p> + * + * @param certainty a measure of the uncertainty that the caller is willing + * to tolerate: if the call returns <code>true</code> the probability that + * this BigInteger is prime exceeds <code>(1 - 1/2<sup>certainty</sup>)</code>. + * The execution time of this method is proportional to the value of this + * parameter. + * @return <code>true</code> if this BigInteger is probably prime, + * <code>false</code> if it's definitely composite. + */ + public boolean isProbablePrime(int certainty) + { + if (certainty < 1) + return true; + + if (USING_NATIVE) + return mpz.testPrimality(certainty) != 0; + + /** We'll use the Rabin-Miller algorithm for doing a probabilistic + * primality test. It is fast, easy and has faster decreasing odds of a + * composite passing than with other tests. This means that this + * method will actually have a probability much greater than the + * 1 - .5^certainty specified in the JCL (p. 117), but I don't think + * anyone will complain about better performance with greater certainty. + * + * The Rabin-Miller algorithm can be found on pp. 259-261 of "Applied + * Cryptography, Second Edition" by Bruce Schneier. + */ + + // First rule out small prime factors + BigInteger rem = new BigInteger(); + int i; + for (i = 0; i < primes.length; i++) + { + if (words == null && ival == primes[i]) + return true; + + divide(this, smallFixNums[primes[i] - minFixNum], null, rem, TRUNCATE); + if (rem.canonicalize().isZero()) + return false; + } + + // Now perform the Rabin-Miller test. + + // Set b to the number of times 2 evenly divides (this - 1). + // I.e. 2^b is the largest power of 2 that divides (this - 1). + BigInteger pMinus1 = add(this, -1); + int b = pMinus1.getLowestSetBit(); + + // Set m such that this = 1 + 2^b * m. + BigInteger m = pMinus1.divide(valueOf(2L).pow(b)); + + // The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Note + // 4.49 (controlling the error probability) gives the number of trials + // for an error probability of 1/2**80, given the number of bits in the + // number to test. we shall use these numbers as is if/when 'certainty' + // is less or equal to 80, and twice as much if it's greater. + int bits = this.bitLength(); + for (i = 0; i < k.length; i++) + if (bits <= k[i]) + break; + int trials = t[i]; + if (certainty > 80) + trials *= 2; + BigInteger z; + for (int t = 0; t < trials; t++) + { + // The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. + // Remark 4.28 states: "...A strategy that is sometimes employed + // is to fix the bases a to be the first few primes instead of + // choosing them at random. + z = smallFixNums[primes[t] - minFixNum].modPow(m, this); + if (z.isOne() || z.equals(pMinus1)) + continue; // Passes the test; may be prime. + + for (i = 0; i < b; ) + { + if (z.isOne()) + return false; + i++; + if (z.equals(pMinus1)) + break; // Passes the test; may be prime. + + z = z.modPow(valueOf(2), this); + } + + if (i == b && !z.equals(pMinus1)) + return false; + } + return true; + } + + private void setInvert() + { + if (words == null) + ival = ~ival; + else + { + for (int i = ival; --i >= 0; ) + words[i] = ~words[i]; + } + } + + private void setShiftLeft(BigInteger x, int count) + { + int[] xwords; + int xlen; + if (x.words == null) + { + if (count < 32) + { + set((long) x.ival << count); + return; + } + xwords = new int[1]; + xwords[0] = x.ival; + xlen = 1; + } + else + { + xwords = x.words; + xlen = x.ival; + } + int word_count = count >> 5; + count &= 31; + int new_len = xlen + word_count; + if (count == 0) + { + realloc(new_len); + for (int i = xlen; --i >= 0; ) + words[i+word_count] = xwords[i]; + } + else + { + new_len++; + realloc(new_len); + int shift_out = MPN.lshift(words, word_count, xwords, xlen, count); + count = 32 - count; + words[new_len-1] = (shift_out << count) >> count; // sign-extend. + } + ival = new_len; + for (int i = word_count; --i >= 0; ) + words[i] = 0; + } + + private void setShiftRight(BigInteger x, int count) + { + if (x.words == null) + set(count < 32 ? x.ival >> count : x.ival < 0 ? -1 : 0); + else if (count == 0) + set(x); + else + { + boolean neg = x.isNegative(); + int word_count = count >> 5; + count &= 31; + int d_len = x.ival - word_count; + if (d_len <= 0) + set(neg ? -1 : 0); + else + { + if (words == null || words.length < d_len) + realloc(d_len); + MPN.rshift0 (words, x.words, word_count, d_len, count); + ival = d_len; + if (neg) + words[d_len-1] |= -2 << (31 - count); + } + } + } + + private void setShift(BigInteger x, int count) + { + if (count > 0) + setShiftLeft(x, count); + else + setShiftRight(x, -count); + } + + private static BigInteger shift(BigInteger x, int count) + { + if (x.words == null) + { + if (count <= 0) + return valueOf(count > -32 ? x.ival >> (-count) : x.ival < 0 ? -1 : 0); + if (count < 32) + return valueOf((long) x.ival << count); + } + if (count == 0) + return x; + BigInteger result = new BigInteger(0); + result.setShift(x, count); + return result.canonicalize(); + } + + public BigInteger shiftLeft(int n) + { + if (n == 0) + return this; + + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + if (n < 0) + mpz.shiftRight(-n, result.mpz); + else + mpz.shiftLeft(n, result.mpz); + return result; + } + + return shift(this, n); + } + + public BigInteger shiftRight(int n) + { + if (n == 0) + return this; + + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + if (n < 0) + mpz.shiftLeft(-n, result.mpz); + else + mpz.shiftRight(n, result.mpz); + return result; + } + + return shift(this, -n); + } + + private void format(int radix, CPStringBuilder buffer) + { + if (words == null) + buffer.append(Integer.toString(ival, radix)); + else if (ival <= 2) + buffer.append(Long.toString(longValue(), radix)); + else + { + boolean neg = isNegative(); + int[] work; + if (neg || radix != 16) + { + work = new int[ival]; + getAbsolute(work); + } + else + work = words; + int len = ival; + + if (radix == 16) + { + if (neg) + buffer.append('-'); + int buf_start = buffer.length(); + for (int i = len; --i >= 0; ) + { + int word = work[i]; + for (int j = 8; --j >= 0; ) + { + int hex_digit = (word >> (4 * j)) & 0xF; + // Suppress leading zeros: + if (hex_digit > 0 || buffer.length() > buf_start) + buffer.append(Character.forDigit(hex_digit, 16)); + } + } + } + else + { + int i = buffer.length(); + for (;;) + { + int digit = MPN.divmod_1(work, work, len, radix); + buffer.append(Character.forDigit(digit, radix)); + while (len > 0 && work[len-1] == 0) len--; + if (len == 0) + break; + } + if (neg) + buffer.append('-'); + /* Reverse buffer. */ + int j = buffer.length() - 1; + while (i < j) + { + char tmp = buffer.charAt(i); + buffer.setCharAt(i, buffer.charAt(j)); + buffer.setCharAt(j, tmp); + i++; j--; + } + } + } + } + + public String toString() + { + return toString(10); + } + + public String toString(int radix) + { + if (USING_NATIVE) + return mpz.toString(radix); + + if (words == null) + return Integer.toString(ival, radix); + if (ival <= 2) + return Long.toString(longValue(), radix); + int buf_size = ival * (MPN.chars_per_word(radix) + 1); + CPStringBuilder buffer = new CPStringBuilder(buf_size); + format(radix, buffer); + return buffer.toString(); + } + + public int intValue() + { + if (USING_NATIVE) + { + int result = mpz.absIntValue(); + return mpz.compare(ZERO.mpz) < 0 ? - result : result; + } + + if (words == null) + return ival; + return words[0]; + } + + public long longValue() + { + if (USING_NATIVE) + { + long result; + result = (abs().shiftRight(32)).mpz.absIntValue(); + result <<= 32; + result |= mpz.absIntValue() & 0xFFFFFFFFL; + return this.compareTo(ZERO) < 0 ? - result : result; + } + + if (words == null) + return ival; + if (ival == 1) + return words[0]; + return ((long)words[1] << 32) + ((long)words[0] & 0xffffffffL); + } + + public int hashCode() + { + // FIXME: May not match hashcode of JDK. + if (USING_NATIVE) + { + // TODO: profile to decide whether to make it native + byte[] bytes = this.toByteArray(); + int result = 0; + for (int i = 0; i < bytes.length; i++) + result ^= (bytes[i] & 0xFF) << (8 * (i % 4)); + return result; + } + + return words == null ? ival : (words[0] + words[ival - 1]); + } + + /* Assumes x and y are both canonicalized. */ + private static boolean equals(BigInteger x, BigInteger y) + { + if (USING_NATIVE) + return x.mpz.compare(y.mpz) == 0; + + if (x.words == null && y.words == null) + return x.ival == y.ival; + if (x.words == null || y.words == null || x.ival != y.ival) + return false; + for (int i = x.ival; --i >= 0; ) + { + if (x.words[i] != y.words[i]) + return false; + } + return true; + } + + /* Assumes this and obj are both canonicalized. */ + public boolean equals(Object obj) + { + if (! (obj instanceof BigInteger)) + return false; + return equals(this, (BigInteger) obj); + } + + private static BigInteger valueOf(byte[] digits, int byte_len, + boolean negative, int radix) + { + int chars_per_word = MPN.chars_per_word(radix); + int[] words = new int[byte_len / chars_per_word + 1]; + int size = MPN.set_str(words, digits, byte_len, radix); + if (size == 0) + return ZERO; + if (words[size-1] < 0) + words[size++] = 0; + if (negative) + negate(words, words, size); + return make(words, size); + } + + public double doubleValue() + { + if (USING_NATIVE) + return mpz.doubleValue(); + + if (words == null) + return (double) ival; + if (ival <= 2) + return (double) longValue(); + if (isNegative()) + return neg(this).roundToDouble(0, true, false); + return roundToDouble(0, false, false); + } + + public float floatValue() + { + return (float) doubleValue(); + } + + /** Return true if any of the lowest n bits are one. + * (false if n is negative). */ + private boolean checkBits(int n) + { + if (n <= 0) + return false; + if (words == null) + return n > 31 || ((ival & ((1 << n) - 1)) != 0); + int i; + for (i = 0; i < (n >> 5) ; i++) + if (words[i] != 0) + return true; + return (n & 31) != 0 && (words[i] & ((1 << (n & 31)) - 1)) != 0; + } + + /** Convert a semi-processed BigInteger to double. + * Number must be non-negative. Multiplies by a power of two, applies sign, + * and converts to double, with the usual java rounding. + * @param exp power of two, positive or negative, by which to multiply + * @param neg true if negative + * @param remainder true if the BigInteger is the result of a truncating + * division that had non-zero remainder. To ensure proper rounding in + * this case, the BigInteger must have at least 54 bits. */ + private double roundToDouble(int exp, boolean neg, boolean remainder) + { + // Compute length. + int il = bitLength(); + + // Exponent when normalized to have decimal point directly after + // leading one. This is stored excess 1023 in the exponent bit field. + exp += il - 1; + + // Gross underflow. If exp == -1075, we let the rounding + // computation determine whether it is minval or 0 (which are just + // 0x0000 0000 0000 0001 and 0x0000 0000 0000 0000 as bit + // patterns). + if (exp < -1075) + return neg ? -0.0 : 0.0; + + // gross overflow + if (exp > 1023) + return neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + + // number of bits in mantissa, including the leading one. + // 53 unless it's denormalized + int ml = (exp >= -1022 ? 53 : 53 + exp + 1022); + + // Get top ml + 1 bits. The extra one is for rounding. + long m; + int excess_bits = il - (ml + 1); + if (excess_bits > 0) + m = ((words == null) ? ival >> excess_bits + : MPN.rshift_long(words, ival, excess_bits)); + else + m = longValue() << (- excess_bits); + + // Special rounding for maxval. If the number exceeds maxval by + // any amount, even if it's less than half a step, it overflows. + if (exp == 1023 && ((m >> 1) == (1L << 53) - 1)) + { + if (remainder || checkBits(il - ml)) + return neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + else + return neg ? - Double.MAX_VALUE : Double.MAX_VALUE; + } + + // Normal round-to-even rule: round up if the bit dropped is a one, and + // the bit above it or any of the bits below it is a one. + if ((m & 1) == 1 + && ((m & 2) == 2 || remainder || checkBits(excess_bits))) + { + m += 2; + // Check if we overflowed the mantissa + if ((m & (1L << 54)) != 0) + { + exp++; + // renormalize + m >>= 1; + } + // Check if a denormalized mantissa was just rounded up to a + // normalized one. + else if (ml == 52 && (m & (1L << 53)) != 0) + exp++; + } + + // Discard the rounding bit + m >>= 1; + + long bits_sign = neg ? (1L << 63) : 0; + exp += 1023; + long bits_exp = (exp <= 0) ? 0 : ((long)exp) << 52; + long bits_mant = m & ~(1L << 52); + return Double.longBitsToDouble(bits_sign | bits_exp | bits_mant); + } + + /** Copy the abolute value of this into an array of words. + * Assumes words.length >= (this.words == null ? 1 : this.ival). + * Result is zero-extended, but need not be a valid 2's complement number. + */ + private void getAbsolute(int[] words) + { + int len; + if (this.words == null) + { + len = 1; + words[0] = this.ival; + } + else + { + len = this.ival; + for (int i = len; --i >= 0; ) + words[i] = this.words[i]; + } + if (words[len - 1] < 0) + negate(words, words, len); + for (int i = words.length; --i > len; ) + words[i] = 0; + } + + /** Set dest[0:len-1] to the negation of src[0:len-1]. + * Return true if overflow (i.e. if src is -2**(32*len-1)). + * Ok for src==dest. */ + private static boolean negate(int[] dest, int[] src, int len) + { + long carry = 1; + boolean negative = src[len-1] < 0; + for (int i = 0; i < len; i++) + { + carry += ((long) (~src[i]) & 0xffffffffL); + dest[i] = (int) carry; + carry >>= 32; + } + return (negative && dest[len-1] < 0); + } + + /** Destructively set this to the negative of x. + * It is OK if x==this.*/ + private void setNegative(BigInteger x) + { + int len = x.ival; + if (x.words == null) + { + if (len == Integer.MIN_VALUE) + set(- (long) len); + else + set(-len); + return; + } + realloc(len + 1); + if (negate(words, x.words, len)) + words[len++] = 0; + ival = len; + } + + /** Destructively negate this. */ + private void setNegative() + { + setNegative(this); + } + + private static BigInteger abs(BigInteger x) + { + return x.isNegative() ? neg(x) : x; + } + + public BigInteger abs() + { + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.abs(result.mpz); + return result; + } + + return abs(this); + } + + private static BigInteger neg(BigInteger x) + { + if (x.words == null && x.ival != Integer.MIN_VALUE) + return valueOf(- x.ival); + BigInteger result = new BigInteger(0); + result.setNegative(x); + return result.canonicalize(); + } + + public BigInteger negate() + { + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.negate(result.mpz); + return result; + } + + return neg(this); + } + + /** Calculates ceiling(log2(this < 0 ? -this : this+1)) + * See Common Lisp: the Language, 2nd ed, p. 361. + */ + public int bitLength() + { + if (USING_NATIVE) + return mpz.bitLength(); + + if (words == null) + return MPN.intLength(ival); + return MPN.intLength(words, ival); + } + + public byte[] toByteArray() + { + if (signum() == 0) + return new byte[1]; + + if (USING_NATIVE) + { + // the minimal number of bytes required to represent the MPI is function + // of (a) its bit-length, and (b) its sign. only when this MPI is both + // positive, and its bit-length is a multiple of 8 do we add one zero + // bit for its sign. we do this so if we construct a new MPI from the + // resulting byte array, we wouldn't mistake a positive number, whose + // bit-length is a multiple of 8, for a similar-length negative one. + int bits = bitLength(); + if (bits % 8 == 0 || this.signum() == 1) + bits++; + byte[] bytes = new byte[(bits + 7) / 8]; + mpz.toByteArray(bytes); + return bytes; + } + + // Determine number of bytes needed. The method bitlength returns + // the size without the sign bit, so add one bit for that and then + // add 7 more to emulate the ceil function using integer math. + byte[] bytes = new byte[(bitLength() + 1 + 7) / 8]; + int nbytes = bytes.length; + + int wptr = 0; + int word; + + // Deal with words array until one word or less is left to process. + // If BigInteger is an int, then it is in ival and nbytes will be <= 4. + while (nbytes > 4) + { + word = words[wptr++]; + for (int i = 4; i > 0; --i, word >>= 8) + bytes[--nbytes] = (byte) word; + } + + // Deal with the last few bytes. If BigInteger is an int, use ival. + word = (words == null) ? ival : words[wptr]; + for ( ; nbytes > 0; word >>= 8) + bytes[--nbytes] = (byte) word; + + return bytes; + } + + /** Return the boolean opcode (for bitOp) for swapped operands. + * I.e. bitOp(swappedOp(op), x, y) == bitOp(op, y, x). + */ + private static int swappedOp(int op) + { + return + "\000\001\004\005\002\003\006\007\010\011\014\015\012\013\016\017" + .charAt(op); + } + + /** Do one the the 16 possible bit-wise operations of two BigIntegers. */ + private static BigInteger bitOp(int op, BigInteger x, BigInteger y) + { + switch (op) + { + case 0: return ZERO; + case 1: return x.and(y); + case 3: return x; + case 5: return y; + case 15: return valueOf(-1); + } + BigInteger result = new BigInteger(); + setBitOp(result, op, x, y); + return result.canonicalize(); + } + + /** Do one the the 16 possible bit-wise operations of two BigIntegers. */ + private static void setBitOp(BigInteger result, int op, + BigInteger x, BigInteger y) + { + if ((y.words != null) && (x.words == null || x.ival < y.ival)) + { + BigInteger temp = x; x = y; y = temp; + op = swappedOp(op); + } + int xi; + int yi; + int xlen, ylen; + if (y.words == null) + { + yi = y.ival; + ylen = 1; + } + else + { + yi = y.words[0]; + ylen = y.ival; + } + if (x.words == null) + { + xi = x.ival; + xlen = 1; + } + else + { + xi = x.words[0]; + xlen = x.ival; + } + if (xlen > 1) + result.realloc(xlen); + int[] w = result.words; + int i = 0; + // Code for how to handle the remainder of x. + // 0: Truncate to length of y. + // 1: Copy rest of x. + // 2: Invert rest of x. + int finish = 0; + int ni; + switch (op) + { + case 0: // clr + ni = 0; + break; + case 1: // and + for (;;) + { + ni = xi & yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 1; + break; + case 2: // andc2 + for (;;) + { + ni = xi & ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 1; + break; + case 3: // copy x + ni = xi; + finish = 1; // Copy rest + break; + case 4: // andc1 + for (;;) + { + ni = ~xi & yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 2; + break; + case 5: // copy y + for (;;) + { + ni = yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + break; + case 6: // xor + for (;;) + { + ni = xi ^ yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + finish = yi < 0 ? 2 : 1; + break; + case 7: // ior + for (;;) + { + ni = xi | yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 1; + break; + case 8: // nor + for (;;) + { + ni = ~(xi | yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 2; + break; + case 9: // eqv [exclusive nor] + for (;;) + { + ni = ~(xi ^ yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + finish = yi >= 0 ? 2 : 1; + break; + case 10: // c2 + for (;;) + { + ni = ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + break; + case 11: // orc2 + for (;;) + { + ni = xi | ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 1; + break; + case 12: // c1 + ni = ~xi; + finish = 2; + break; + case 13: // orc1 + for (;;) + { + ni = ~xi | yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 2; + break; + case 14: // nand + for (;;) + { + ni = ~(xi & yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 2; + break; + default: + case 15: // set + ni = -1; + break; + } + // Here i==ylen-1; w[0]..w[i-1] have the correct result; + // and ni contains the correct result for w[i+1]. + if (i+1 == xlen) + finish = 0; + switch (finish) + { + case 0: + if (i == 0 && w == null) + { + result.ival = ni; + return; + } + w[i++] = ni; + break; + case 1: w[i] = ni; while (++i < xlen) w[i] = x.words[i]; break; + case 2: w[i] = ni; while (++i < xlen) w[i] = ~x.words[i]; break; + } + result.ival = i; + } + + /** Return the logical (bit-wise) "and" of a BigInteger and an int. */ + private static BigInteger and(BigInteger x, int y) + { + if (x.words == null) + return valueOf(x.ival & y); + if (y >= 0) + return valueOf(x.words[0] & y); + int len = x.ival; + int[] words = new int[len]; + words[0] = x.words[0] & y; + while (--len > 0) + words[len] = x.words[len]; + return make(words, x.ival); + } + + /** Return the logical (bit-wise) "and" of two BigIntegers. */ + public BigInteger and(BigInteger y) + { + if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.and(y.mpz, result.mpz); + return result; + } + + if (y.words == null) + return and(this, y.ival); + else if (words == null) + return and(y, ival); + + BigInteger x = this; + if (ival < y.ival) + { + BigInteger temp = this; x = y; y = temp; + } + int i; + int len = y.isNegative() ? x.ival : y.ival; + int[] words = new int[len]; + for (i = 0; i < y.ival; i++) + words[i] = x.words[i] & y.words[i]; + for ( ; i < len; i++) + words[i] = x.words[i]; + return make(words, len); + } + + /** Return the logical (bit-wise) "(inclusive) or" of two BigIntegers. */ + public BigInteger or(BigInteger y) + { + if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.or(y.mpz, result.mpz); + return result; + } + + return bitOp(7, this, y); + } + + /** Return the logical (bit-wise) "exclusive or" of two BigIntegers. */ + public BigInteger xor(BigInteger y) + { + if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.xor(y.mpz, result.mpz); + return result; + } + + return bitOp(6, this, y); + } + + /** Return the logical (bit-wise) negation of a BigInteger. */ + public BigInteger not() + { + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.not(result.mpz); + return result; + } + + return bitOp(12, this, ZERO); + } + + public BigInteger andNot(BigInteger val) + { + if (USING_NATIVE) + { + int dummy = val.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.andNot(val.mpz, result.mpz); + return result; + } + + return and(val.not()); + } + + public BigInteger clearBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.setBit(n, false, result.mpz); + return result; + } + + return and(ONE.shiftLeft(n).not()); + } + + public BigInteger setBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.setBit(n, true, result.mpz); + return result; + } + + return or(ONE.shiftLeft(n)); + } + + public boolean testBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + if (USING_NATIVE) + return mpz.testBit(n) != 0; + + return !and(ONE.shiftLeft(n)).isZero(); + } + + public BigInteger flipBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.flipBit(n, result.mpz); + return result; + } + + return xor(ONE.shiftLeft(n)); + } + + public int getLowestSetBit() + { + if (USING_NATIVE) + return mpz.compare(ZERO.mpz) == 0 ? -1 : mpz.lowestSetBit(); + + if (isZero()) + return -1; + + if (words == null) + return MPN.findLowestBit(ival); + else + return MPN.findLowestBit(words); + } + + // bit4count[I] is number of '1' bits in I. + private static final byte[] bit4_count = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4}; + + private static int bitCount(int i) + { + int count = 0; + while (i != 0) + { + count += bit4_count[i & 15]; + i >>>= 4; + } + return count; + } + + private static int bitCount(int[] x, int len) + { + int count = 0; + while (--len >= 0) + count += bitCount(x[len]); + return count; + } + + /** Count one bits in a BigInteger. + * If argument is negative, count zero bits instead. */ + public int bitCount() + { + if (USING_NATIVE) + return mpz.bitCount(); + + int i, x_len; + int[] x_words = words; + if (x_words == null) + { + x_len = 1; + i = bitCount(ival); + } + else + { + x_len = ival; + i = bitCount(x_words, x_len); + } + return isNegative() ? x_len * 32 - i : i; + } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + if (USING_NATIVE) + { + mpz = new GMP(); + s.defaultReadObject(); + if (signum != 0) + mpz.fromByteArray(magnitude); + // else it's zero and we need to do nothing + } + else + { + s.defaultReadObject(); + if (magnitude.length == 0 || signum == 0) + { + this.ival = 0; + this.words = null; + } + else + { + words = byteArrayToIntArray(magnitude, signum < 0 ? -1 : 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + } + } + } + + private void writeObject(ObjectOutputStream s) + throws IOException, ClassNotFoundException + { + signum = signum(); + magnitude = signum == 0 ? new byte[0] : toByteArray(); + s.defaultWriteObject(); + magnitude = null; // not needed anymore + } + + // inner class(es) .......................................................... + +} diff --git a/libjava/classpath/java/math/MathContext.java b/libjava/classpath/java/math/MathContext.java new file mode 100644 index 000000000..161149540 --- /dev/null +++ b/libjava/classpath/java/math/MathContext.java @@ -0,0 +1,198 @@ +/* MathContext.java -- + Copyright (C) 1999, 2000, 2002, 2004, 2005 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 java.io.Serializable; + +/** + * Immutable objects describing settings such as rounding mode and digit + * precision for numerical operations such as those in the BigDecimal class. + * @author Anthony Balkissoon abalkiss at redhat dot com + * + */ +public final class MathContext implements Serializable +{ + /** A MathContext for unlimited precision arithmetic * */ + public static final MathContext UNLIMITED = + new MathContext(0, RoundingMode.HALF_UP); + + /** + * A MathContext for the IEEE 754R Decimal32 format - 7 digit preicision and + * HALF_EVEN rounding. + */ + public static final MathContext DECIMAL32 = + new MathContext(7, RoundingMode.HALF_EVEN); + + /** + * A MathContext for the IEEE 754R Decimal64 format - 16 digit preicision and + * HALF_EVEN rounding. + */ + public static final MathContext DECIMAL64 = + new MathContext(16, RoundingMode.HALF_EVEN); + + /** + * A MathContext for the IEEE 754R Decimal128 format - 34 digit preicision and + * HALF_EVEN rounding. + */ + public static final MathContext DECIMAL128 = + new MathContext(34, RoundingMode.HALF_EVEN); + + /** + * This is the serialVersionUID reported here: + * java.sun.com/j2se/1.5.0/docs/api/serialized-form.html#java.math.MathContext + */ + private static final long serialVersionUID = 5579720004786848255L; + + private int precision; + + private RoundingMode roundMode; + + /** + * Constructs a new MathContext with the specified precision and with HALF_UP + * rounding. + * @param setPrecision the precision for the new MathContext + * + * @throws IllegalArgumentException if precision is < 0. + */ + public MathContext(int setPrecision) + { + this(setPrecision, RoundingMode.HALF_UP); + } + + /** + * Constructs a new MathContext with the specified precision and rounding + * mode. + * @param setPrecision the precision + * @param setRoundingMode the rounding mode + * + * @throws IllegalArgumentException if precision is < 0. + */ + public MathContext(int setPrecision, RoundingMode setRoundingMode) + { + if (setPrecision < 0) + throw new IllegalArgumentException("Precision cannot be less than zero."); + precision = setPrecision; + roundMode = setRoundingMode; + } + + /** + * Constructs a MathContext from a String that has the same form as one + * produced by the toString() method. + * @param val + * + * @throws IllegalArgumentException if the String is not in the correct + * format or if the precision specified is < 0. + */ + public MathContext(String val) + { + try + { + int roundingModeIndex = val.indexOf("roundingMode", 10); + precision = Integer.parseInt(val.substring(10, roundingModeIndex - 1)); + roundMode = RoundingMode.valueOf(val.substring(roundingModeIndex + 13)); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("String not in correct format"); + } + catch (IllegalArgumentException iae) + { + throw new IllegalArgumentException("String not in correct format"); + } + if (precision < 0) + throw new IllegalArgumentException("Precision cannot be less than 0."); + } + + /** + * Returns true if x is a MathContext and has the same precision setting + * and rounding mode as this MathContext. + * + * @return true if the above conditions hold + */ + public boolean equals(Object x) + { + if (!(x instanceof MathContext)) + return false; + MathContext mc = (MathContext)x; + return mc.precision == this.precision + && mc.roundMode.equals(this.roundMode); + } + + /** + * Returns the precision setting. + * @return the precision setting. + */ + public int getPrecision() + { + return precision; + } + + /** + * Returns the rounding mode setting. This will be one of + * RoundingMode.CEILING, RoundingMode.DOWN, RoundingMode.FLOOR, + * RoundingMode.HALF_DOWN, RoundingMode.HALF_EVEN, RoundingMode.HALF_UP, + * RoundingMode.UNNECESSARY, or RoundingMode.UP. + * @return the rounding mode setting. + */ + public RoundingMode getRoundingMode() + { + return roundMode; + } + + /** + * Returns "precision=p roundingMode=MODE" where p is an int giving the + * precision and MODE is UP, DOWN, HALF_UP, HALF_DOWN, HALF_EVEN, CEILING, + * FLOOR, or UNNECESSARY corresponding to rounding modes. + * + * @return a String describing this MathContext + */ + public String toString() + { + return "precision="+precision+" roundingMode="+roundMode; + } + + /** + * Returns the hashcode for this MathContext. + * @return the hashcode for this MathContext. + */ + public int hashCode() + { + return precision ^ roundMode.hashCode(); + } +} diff --git a/libjava/classpath/java/math/RoundingMode.java b/libjava/classpath/java/math/RoundingMode.java new file mode 100644 index 000000000..140f0a36e --- /dev/null +++ b/libjava/classpath/java/math/RoundingMode.java @@ -0,0 +1,89 @@ +/* RoundingMode.java -- An Enum to replace BigDecimal rounding constants. + Copyright (C) 1999, 2000, 2002, 2004, 2005 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; + +/** + * An enum to specify rounding behaviour for numerical operations that may + * discard precision. + * @author Anthony Balkissoon abalkiss at redhat dot com + * + */ +public enum RoundingMode +{ + UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY; + + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 432302042773881265L; + + /** + * Returns the RoundingMode object corresponding to the legacy rounding modes + * in BigDecimal. + * @param rm the legacy rounding mode + * @return the corresponding RoundingMode + */ + public static RoundingMode valueOf(int rm) + { + switch (rm) + { + case BigDecimal.ROUND_CEILING: + return CEILING; + case BigDecimal.ROUND_FLOOR: + return FLOOR; + case BigDecimal.ROUND_DOWN: + return DOWN; + case BigDecimal.ROUND_UP: + return UP; + case BigDecimal.ROUND_HALF_UP: + return HALF_UP; + case BigDecimal.ROUND_HALF_DOWN: + return HALF_DOWN; + case BigDecimal.ROUND_HALF_EVEN: + return HALF_EVEN; + case BigDecimal.ROUND_UNNECESSARY: + return UNNECESSARY; + default: + throw new + IllegalArgumentException("invalid argument: " + rm + + ". Argument should be one of the " + + "rounding modes defined in BigDecimal."); + } + } +} diff --git a/libjava/classpath/java/math/package.html b/libjava/classpath/java/math/package.html new file mode 100644 index 000000000..62d12ea16 --- /dev/null +++ b/libjava/classpath/java/math/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.math package. + Copyright (C) 2002 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. --> + +<html> +<head><title>GNU Classpath - java.math</title></head> + +<body> +<p>Arbitrary large decimals and integers.</p> + +</body> +</html> |