Return-Path: Delivered-To: apmail-incubator-harmony-commits-archive@www.apache.org Received: (qmail 14715 invoked from network); 16 Aug 2006 11:56:38 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 16 Aug 2006 11:56:38 -0000 Received: (qmail 78768 invoked by uid 500); 16 Aug 2006 11:56:38 -0000 Delivered-To: apmail-incubator-harmony-commits-archive@incubator.apache.org Received: (qmail 78736 invoked by uid 500); 16 Aug 2006 11:56:38 -0000 Mailing-List: contact harmony-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: harmony-dev@incubator.apache.org Delivered-To: mailing list harmony-commits@incubator.apache.org Received: (qmail 78725 invoked by uid 99); 16 Aug 2006 11:56:37 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 Aug 2006 04:56:37 -0700 X-ASF-Spam-Status: No, hits=-7.8 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME,OBSCURED_EMAIL X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 Aug 2006 04:56:33 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 22F961A981A; Wed, 16 Aug 2006 04:56:13 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: svn commit: r431881 [1/3] - in /incubator/harmony/enhanced/classlib/trunk/modules: luni/src/main/java/java/lang/ math/src/main/java/java/math/ math/src/main/resources/ math/src/test/java/org/apache/harmony/tests/java/math/ math2/ Date: Wed, 16 Aug 2006 11:56:04 -0000 To: harmony-commits@incubator.apache.org From: mloenko@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060816115613.22F961A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: mloenko Date: Wed Aug 16 04:55:59 2006 New Revision: 431881 URL: http://svn.apache.org/viewvc?rev=431881&view=rev Log: integrated src.zip from HARMONY-935 [classlib][java.math] combination of math packages The tests and new sources were adjusted to match each other Had to add a method into luni module Added: incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BigDecimal.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BigInteger.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BitLevel.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/Conversion.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/Division.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/Elementary.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/Logical.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/MathContext.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/Multiplication.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/Primality.java (with props) incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/RoundingMode.java (with props) Removed: incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/resources/ incubator/harmony/enhanced/classlib/trunk/modules/math2/ Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/lang/Math.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigDecimalArithmeticTest.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigDecimalConstructorsTest.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigDecimalScaleOperationsTest.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigIntegerConstructorsTest.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigIntegerDivideTest.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigIntegerModPowTest.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigIntegerMultiplyTest.java incubator/harmony/enhanced/classlib/trunk/modules/math/src/test/java/org/apache/harmony/tests/java/math/BigIntegerOperateBitsTest.java Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/lang/Math.java URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/lang/Math.java?rev=431881&r1=431880&r2=431881&view=diff ============================================================================== --- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/lang/Math.java (original) +++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/lang/Math.java Wed Aug 16 04:55:59 2006 @@ -191,6 +191,19 @@ */ public static native double log(double d); + /** + * Answers the closest double approximation of the base 10 logarithm of the + * argument + * + * @param d + * the value to compute the log10 of + * @return the natural logarithm of the argument. + */ + public static double log10(double d) { + //TODO: this is a stub to integrate HARMONY-935 + return log(d)/log(10); + } + /** * Answers the most positive (i.e. closest to positive infinity) of the two * arguments. Added: incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BigDecimal.java URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BigDecimal.java?rev=431881&view=auto ============================================================================== --- incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BigDecimal.java (added) +++ incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BigDecimal.java Wed Aug 16 04:55:59 2006 @@ -0,0 +1,1790 @@ +/* + * Copyright 2005, 2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.math; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.io.StreamCorruptedException; + +/** + * @author Daniel Fridlender + * @author Matthias Gallé + * @author Mariano Heredia + * @author Miguel Vasquez + * + * @ar.org.fitc.spec_ref + */ +public class BigDecimal extends Number implements Comparable, + Serializable { + + /* Static Fields */ + + /** @ar.org.fitc.spec_ref */ + public static final BigDecimal ZERO = new BigDecimal(BigInteger.ZERO, 0); + + /** @ar.org.fitc.spec_ref */ + public static final BigDecimal ONE = new BigDecimal(BigInteger.ONE, 0); + + /** @ar.org.fitc.spec_ref */ + public static final BigDecimal TEN = new BigDecimal(BigInteger.TEN, 0); + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_UP = 0; + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_DOWN = 1; + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_CEILING = 2; + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_FLOOR = 3; + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_HALF_UP = 4; + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_HALF_DOWN = 5; + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_HALF_EVEN = 6; + + /** @ar.org.fitc.spec_ref */ + public static final int ROUND_UNNECESSARY = 7; + + /* Private Fields */ + + /** @ar.org.fitc.spec_ref */ + private static final long serialVersionUID = 6108874887143696463L; + + /** The double closer to Log10(2). */ + private static final double LOG10_2 = 0.3010299956639812; + + /** The String representation is cached. */ + private transient String toStringImage = null; + + /** + * An array with powers of five that fit in the type long + * (5^0,5^1,...,5^27) + */ + private static final BigInteger FIVE_POW[] = new BigInteger[28]; + + /** + * An array with powers of ten that fit in the type long + * (10^0,10^1,...,10^18) + */ + private static final BigInteger TEN_POW[] = new BigInteger[19]; + + /** + * An array with the first BigInteger scaled by zero. + * ([0,0],[1,0],...,[10,0]) + */ + private static final BigDecimal BI_SCALED_BY_ZERO[] = new BigDecimal[11]; + + /** + * An array with the zero number scaled by the first positive scales. + * (0*10^0, 0*10^1, ..., 0*10^10) + */ + private static final BigDecimal ZERO_SCALED_BY[] = new BigDecimal[11]; + + /** An array filled with characters '0'. */ + private static final char[] CH_ZEROS = new char[100]; + + static { + // To fill all static arrays. + int i = 0; + long fivePow = 1; + + for (; i < ZERO_SCALED_BY.length; i++) { + BI_SCALED_BY_ZERO[i] = new BigDecimal(BigInteger.valueOf(i), 0); + ZERO_SCALED_BY[i] = new BigDecimal(BigInteger.ZERO, i); + FIVE_POW[i] = BigInteger.valueOf(fivePow); + TEN_POW[i] = BigInteger.valueOf(fivePow << i); + CH_ZEROS[i] = '0'; + fivePow *= 5; + } + for (; i < TEN_POW.length; i++) { + FIVE_POW[i] = BigInteger.valueOf(fivePow); + TEN_POW[i] = BigInteger.valueOf(fivePow << i); + CH_ZEROS[i] = '0'; + fivePow *= 5; + } + for (; i < FIVE_POW.length; i++) { + FIVE_POW[i] = BigInteger.valueOf(fivePow); + CH_ZEROS[i] = '0'; + fivePow *= 5; + } + for (; i < CH_ZEROS.length; i++) { + CH_ZEROS[i] = '0'; + } + } + + /** + * The arbitrary precision integer (unscaled value) in the internal + * representation of BigDecimal. + */ + private BigInteger unscaledValue; + + /** + * The 32-bit integer scale in the internal representation of BigDecimal. + */ + private int scale; + + /** + * Represent the number of decimal digits in the unscaled value. This + * precision is calculated the first time, and used in the following + * calls of method precision(). Note that some call to + * the private method inplaceRound() could update this field. + * @see #precision() + * @see #inplaceRound(MathContext) + */ + private int precision = 0; + + /* Constructors */ + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(char[] in, int offset, int len) { + int begin = offset; // first index to be copied + int last = offset + (len - 1); // last index to be copied + String scaleString = null; // buffer for scale + StringBuffer unscaledBuffer; // buffer for unscaled value + long newScale; // the new scale + + if (in == null) { + throw new NullPointerException(); + } + if ((last >= in.length) || (offset < 0) || (len <= 0) || (last < 0)) { + throw new NumberFormatException(); + } + unscaledBuffer = new StringBuffer(len); + // To skip a possible '+' symbol + if ((offset <= last) && (in[offset] == '+')) { + offset++; + begin++; + } + // Acumulating all digits until a possible decimal point + for (; (offset <= last) && (in[offset] != '.') && (in[offset] != 'e') + && (in[offset] != 'E'); offset++) + ; + unscaledBuffer.append(in, begin, offset - begin); + // A decimal point was found + if ((offset <= last) && (in[offset] == '.')) { + offset++; + // Acumulating all digits until a possible exponent + begin = offset; + for (; (offset <= last) && (in[offset] != 'e') + && (in[offset] != 'E'); offset++) + ; + scale = offset - begin; + unscaledBuffer.append(in, begin, scale); + } else { + scale = 0; + } + // An exponent was found + if ((offset <= last) && ((in[offset] == 'e') || (in[offset] == 'E'))) { + offset++; + // Checking for a posible sign of scale + begin = offset; + if ((offset <= last) && (in[offset] == '+')) { + offset++; + if ((offset <= last) && (in[offset] != '-')) { + begin++; + } + } + // Acumulating all reminaining digits + scaleString = String.valueOf(in, begin, last + 1 - begin); + // Checking if the scale is defined + newScale = (long) scale - Integer.parseInt(scaleString); + scale = (int) newScale; + if (newScale != scale) { + throw new NumberFormatException("Scale out of range."); + } + } + // Parsing the unscaled value + unscaledValue = new BigInteger(unscaledBuffer.toString()); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(char[] in, int offset, int len, MathContext mc) { + this(in, offset, len); + inplaceRound(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(char[] in) { + this(in, 0, in.length); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(char[] in, MathContext mc) { + this(in, 0, in.length); + inplaceRound(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(String val) { + this(val.toCharArray(), 0, val.length()); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(String val, MathContext mc) { + this(val.toCharArray(), 0, val.length()); + inplaceRound(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(double val) { + if (Double.isInfinite(val) || Double.isNaN(val)) { + throw new NumberFormatException("Infinite or NaN"); + } + long bits = Double.doubleToLongBits(val); // IEEE-754 + long mantisa; + int trailingZeros; + // Extracting the exponent, note that the bias is 1023 + scale = 1075 - (int) ((bits >> 52) & 0x7FFL); + // Extracting the 52 bits of the mantisa. + mantisa = (scale == 1075) ? (bits & 0xFFFFFFFFFFFFFL) << 1 + : (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L; + // To simplify all factors '2' in the mantisa + if (scale > 0) { + trailingZeros = Math + .min(scale, Long.numberOfTrailingZeros(mantisa)); + mantisa >>>= trailingZeros; + scale -= trailingZeros; + } + // Calculating the new unscaled value and the new scale + unscaledValue = BigInteger.valueOf(((bits >> 63) == 0) ? mantisa + : -mantisa); + if (scale < 0) { + unscaledValue = unscaledValue.shiftLeft(-scale); + scale = 0; + } else if (scale > 0) { + // m * 2^e = (m * 5^(-e)) * 10^e + unscaledValue = (scale < FIVE_POW.length) ? unscaledValue + .multiply(FIVE_POW[scale]) : unscaledValue + .multiply(FIVE_POW[1].pow(scale)); + } + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(double val, MathContext mc) { + this(val); + inplaceRound(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(BigInteger val) { + this(val, 0); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(BigInteger val, MathContext mc) { + this(val); + inplaceRound(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(BigInteger unscaledVal, int scale) { + unscaledValue = unscaledVal; + this.scale = scale; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) { + this(unscaledVal, scale); + inplaceRound(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(int val) { + this((long) val); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(int val, MathContext mc) { + this((long) val); + inplaceRound(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(long val) { + unscaledValue = BigInteger.valueOf(val); + scale = 0; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal(long val, MathContext mc) { + this(val); + inplaceRound(mc); + } + + /* Public Methods */ + + /** @ar.org.fitc.spec_ref */ + public static BigDecimal valueOf(long unscaledVal, int scale) { + if ((unscaledVal == 0) && (scale >= 0) + && (scale < ZERO_SCALED_BY.length)) { + return ZERO_SCALED_BY[scale]; + } + if ((scale == 0) && (unscaledVal >= 0) + && (unscaledVal < BI_SCALED_BY_ZERO.length)) { + return BI_SCALED_BY_ZERO[(int) unscaledVal]; + } + return new BigDecimal(BigInteger.valueOf(unscaledVal), scale); + } + + /** @ar.org.fitc.spec_ref */ + public static BigDecimal valueOf(long val) { + return valueOf(val, 0); + } + + /** @ar.org.fitc.spec_ref */ + public static BigDecimal valueOf(double val) { + if (Double.isInfinite(val) || Double.isNaN(val)) { + throw new NumberFormatException("Infinity or NaN"); + } + return new BigDecimal(Double.toString(val)); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal add(BigDecimal augend) { + long diffScale = (long) this.scale - augend.scale; + // Fast return when some operand is zero + if (this.signum() == 0) { + if (diffScale <= 0) { + return augend; + } + if (augend.signum() == 0) { + return this; + } + } else if (augend.signum() == 0) { + if (diffScale >= 0) { + return this; + } + } + // Let be: this = [u1,s1] and augend = [u2,s2] + if (diffScale == 0) { + // case s1 == s2: [u1 + u2 , s1] + return new BigDecimal(this.unscaledValue.add(augend.unscaledValue), + this.scale); + } else if (diffScale > 0) { + // case s1 > s2 : [(u1 + u2) * 10 ^ (s1 - s2) , s1] + return new BigDecimal(this.unscaledValue.add(augend.unscaledValue + .multiply(powerOf10(diffScale))), this.scale); + } else {// case s2 > s1 : [(u2 + u1) * 10 ^ (s2 - s1) , s2] + return new BigDecimal(augend.unscaledValue.add(this.unscaledValue + .multiply(powerOf10(-diffScale))), augend.scale); + } + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal add(BigDecimal augend, MathContext mc) { + BigDecimal larger; // operand with the largest unscaled value + BigDecimal smaller; // operand with the smallest unscaled value + BigInteger tempBI; + long diffScale = (long) this.scale - augend.scale; + int largerSignum; + // Some operand is zero or the precision is infinity + if ((augend.signum() == 0) || (this.signum() == 0) + || (mc.getPrecision() == 0)) { + return add(augend).round(mc); + } + // Cases where there is room for optimizations + if (this.aproxPrecision() < diffScale - 1) { + larger = augend; + smaller = this; + } else if (augend.aproxPrecision() < -diffScale - 1) { + larger = this; + smaller = augend; + } else {// No optimization is done + return add(augend).round(mc); + } + if (mc.getPrecision() >= larger.aproxPrecision()) { + // No optimization is done + return add(augend).round(mc); + } + // Cases where it's unnecessary to add two numbers with very different scales + largerSignum = larger.signum(); + if (largerSignum == smaller.signum()) { + tempBI = larger.unscaledValue.multiply(BigInteger.TEN).add( + BigInteger.valueOf(largerSignum)); + } else { + tempBI = larger.unscaledValue.subtract(BigInteger + .valueOf(largerSignum)); + tempBI = tempBI.multiply(BigInteger.TEN).add( + BigInteger.valueOf(largerSignum * 9)); + } + // Rounding the improved adding + larger = new BigDecimal(tempBI, larger.scale + 1); + return larger.round(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal subtract(BigDecimal subtrahend) { + long diffScale = (long) this.scale - subtrahend.scale; + // Fast return when some operand is zero + if (this.signum() == 0) { + if (diffScale <= 0) { + return subtrahend.negate(); + } + if (subtrahend.signum() == 0) { + return this; + } + } else if (subtrahend.signum() == 0) { + if (diffScale >= 0) { + return this; + } + } + // Let be: this = [u1,s1] and subtrahend = [u2,s2] so: + if (diffScale == 0) { + // case s1 = s2 : [u1 - u2 , s1] + return new BigDecimal(this.unscaledValue + .subtract(subtrahend.unscaledValue), this.scale); + } else if (diffScale > 0) { + // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ] + return new BigDecimal(this.unscaledValue + .subtract(subtrahend.unscaledValue + .multiply(powerOf10(diffScale))), this.scale); + } else {// case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ] + return new BigDecimal(this.unscaledValue.multiply( + powerOf10(-diffScale)).subtract(subtrahend.unscaledValue), + subtrahend.scale); + } + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) { + long diffScale = subtrahend.scale - (long) this.scale; + int thisSignum; + BigDecimal leftOperand; // it will be only the left operand (this) + BigInteger tempBI; + // Some operand is zero or the precision is infinity + if ((subtrahend.signum() == 0) || (this.signum() == 0) + || (mc.getPrecision() == 0)) { + return subtract(subtrahend).round(mc); + } + // Now: this != 0 and subtrahend != 0 + if (subtrahend.aproxPrecision() < diffScale - 1) { + // Cases where it is unnecessary to subtract two numbers with very different scales + if (mc.getPrecision() < this.aproxPrecision()) { + thisSignum = this.signum(); + if (thisSignum != subtrahend.signum()) { + tempBI = this.unscaledValue.multiply(BigInteger.TEN).add( + BigInteger.valueOf(thisSignum)); + } else { + tempBI = this.unscaledValue.subtract(BigInteger + .valueOf(thisSignum)); + tempBI = tempBI.multiply(BigInteger.TEN).add( + BigInteger.valueOf(thisSignum * 9)); + } + // Rounding the improved substracting + leftOperand = new BigDecimal(tempBI, this.scale + 1); + return leftOperand.round(mc); + } + } + // No optimization is done + return subtract(subtrahend).round(mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal multiply(BigDecimal multiplicand) { + long newScale = (long) this.scale + multiplicand.scale; + + if ((this.signum() == 0) || (multiplicand.signum() == 0)) { + return zeroScaledBy(newScale); + } else { + /* Let be: this = [u1,s1] and multiplicand = [u2,s2] so: + * this x multiplicand = [ s1 * s2 , s1 + s2 ] */ + return new BigDecimal(this.unscaledValue + .multiply(multiplicand.unscaledValue), toIntScale(newScale)); + } + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) { + BigDecimal result = multiply(multiplicand); + + result.inplaceRound(mc); + return result; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) { + return divide(divisor, scale, RoundingMode.valueOf(roundingMode)); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divide(BigDecimal divisor, int scale, + RoundingMode roundingMode) { + // Let be: this = [u1,s1] and divisor = [u2,s2] + long diffScale = ((long) this.scale - divisor.scale) - (long) scale; + int sign = this.signum() * divisor.signum(); // sign of the result + int compRem; // 'compare to remainder' + BigInteger quotAndRem[] = { this.unscaledValue }; // quotient and remainder + BigInteger scaledDivisor = divisor.unscaledValue; // for scaling of 'u2' + + if (roundingMode == null) { + throw new NullPointerException(); + } + if (divisor.signum() == 0) { + throw new ArithmeticException("BigInteger divide by zero"); + } + if (diffScale > 0) { + // Multiply 'u2' by: 10^((s1 - s2) - scale) + scaledDivisor = scaledDivisor.multiply(powerOf10(diffScale)); + } else if (diffScale < 0) { + // Multiply 'u1' by: 10^(scale - (s1 - s2)) + quotAndRem[0] = quotAndRem[0].multiply(powerOf10(-diffScale)); + } + quotAndRem = quotAndRem[0].divideAndRemainder(scaledDivisor); + // If after division there is a remainder... + if (quotAndRem[1].signum() != 0) { + // Checking if: remainder * 2 >= scaledDivisor + compRem = quotAndRem[1].abs().shiftLeft(1).compareTo( + scaledDivisor.abs()); + compRem = roundingBehavior(quotAndRem[0].testBit(0) ? 1 : 0, sign + * (5 + compRem), roundingMode); + if (compRem != 0) { + quotAndRem[0] = quotAndRem[0].add(BigInteger.valueOf(compRem)); + } + } + // Constructing the result with the appropriate unscaled value + return new BigDecimal(quotAndRem[0], scale); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divide(BigDecimal divisor, int roundingMode) { + return divide(divisor, scale, RoundingMode.valueOf(roundingMode)); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) { + return divide(divisor, scale, roundingMode); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divide(BigDecimal divisor) { + BigInteger p = this.unscaledValue; + BigInteger q = divisor.unscaledValue; + BigInteger gcd; // greatest common divisor between 'p' and 'q' + BigInteger quotAndRem[]; + long diffScale = (long) scale - divisor.scale; + int newScale; // the new scale for final quotient + int k; // number of factors "2" in 'q' + int l = 0; // number of factors "5" in 'q' + int i = 1; + int lastPow = FIVE_POW.length - 1; + + if (divisor.signum() == 0) { + throw new ArithmeticException("BigInteger divide by zero"); + } + if (p.signum() == 0) { + return zeroScaledBy(diffScale); + } + // To divide both by the GCD + gcd = p.gcd(q); + p = p.divide(gcd); + q = q.divide(gcd); + // To simplify all "2" factors of q, dividing by 2^k + k = q.getLowestSetBit(); + q = q.shiftRight(k); + // To simplify all "5" factors of q, dividing by 5^l + do { + quotAndRem = q.divideAndRemainder(FIVE_POW[i]); + if (quotAndRem[1].signum() == 0) { + l += i; + if (i < lastPow) { + i++; + } + q = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } while (true); + // If abs(q) != 1 then the quotient is periodic + if (!q.abs().equals(BigInteger.ONE)) { + throw new ArithmeticException("Non-terminating decimal expansion;" + + " no exact representable decimal result."); + } + // The sign of the is fixed and the quotient will be saved in 'p' + if (q.signum() < 0) { + p = p.negate(); + } + // Checking if the new scale is out of range + newScale = toIntScale(diffScale + Math.max(k, l)); + // k >= 0 and l >= 0 implies that k - l is in the 32-bit range + i = k - l; + p = (i >= FIVE_POW.length) ? p.multiply(FIVE_POW[1].pow(i)) + : (i > 0) ? p.multiply(FIVE_POW[i]) : p.shiftLeft(i); + return new BigDecimal(p, newScale); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divide(BigDecimal divisor, MathContext mc) { + /* Calculating how many zeros must be append to 'dividend' + * to obtain a quotient with at least 'mc.precision()' digits */ + long traillingZeros = (long) mc.getPrecision() + 2L + + (long) divisor.aproxPrecision() - (long) aproxPrecision(); + long diffScale = (long) scale - divisor.scale; + long newScale = diffScale; // scale of the final quotient + int compRem; // to compare the remainder + int i = 1; // index + int lastPow = TEN_POW.length - 1; // last power of ten + BigInteger integerQuot; // for temporal results + BigInteger quotAndRem[] = { unscaledValue }; + // In special cases it reduces the problem to call the dual method + if ((mc.getPrecision() == 0) || (this.signum() == 0) + || (divisor.signum() == 0)) { + return this.divide(divisor); + } + if (traillingZeros > 0) { + // To append trailing zeros at end of dividend + quotAndRem[0] = unscaledValue.multiply(powerOf10(traillingZeros)); + newScale += traillingZeros; + } + quotAndRem = quotAndRem[0].divideAndRemainder(divisor.unscaledValue); + integerQuot = quotAndRem[0]; + // Calculating the exact quotient with at least 'mc.precision()' digits + if (quotAndRem[1].signum() != 0) { + // Checking if: 2 * remainder >= divisor ? + compRem = quotAndRem[1].shiftLeft(1).compareTo( + divisor.unscaledValue); + // quot := quot * 10 + r; with 'r' in {-6,-5,-4, 0,+4,+5,+6} + integerQuot = integerQuot.multiply(BigInteger.TEN).add( + BigInteger.valueOf(quotAndRem[0].signum() * (5 + compRem))); + newScale++; + } else { + // To strip trailing zeros until the preferred scale is reached + while (!integerQuot.testBit(0)) { + quotAndRem = integerQuot.divideAndRemainder(TEN_POW[i]); + if ((quotAndRem[1].signum() == 0) + && (newScale - i >= diffScale)) { + newScale -= i; + if (i < lastPow) { + i++; + } + integerQuot = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } + } + // To perform rounding + return new BigDecimal(integerQuot, toIntScale(newScale), mc); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divideToIntegralValue(BigDecimal divisor) { + BigInteger integralValue; // the integer of result + BigInteger powerOfTen; // some power of ten + BigInteger quotAndRem[] = { unscaledValue }; + long newScale = (long) this.scale - divisor.scale; + long tempScale = 0; + int i = 1; + int lastPow = TEN_POW.length - 1; + + if (divisor.signum() == 0) { + throw new ArithmeticException("BigInteger divide by zero"); + } + if ((divisor.aproxPrecision() + newScale > this.aproxPrecision() + 1L) + || (this.signum() == 0)) { + /* If the divisor's integer part is greater than this's integer part, + * the result must be zero with the apropriate scale */ + integralValue = BigInteger.ZERO; + } else if (newScale == 0) { + integralValue = unscaledValue.divide(divisor.unscaledValue); + } else if (newScale > 0) { + powerOfTen = powerOf10(newScale); + integralValue = unscaledValue.divide(divisor.unscaledValue + .multiply(powerOfTen)); + integralValue = integralValue.multiply(powerOfTen); + } else {// (newScale < 0) + powerOfTen = powerOf10(-newScale); + integralValue = unscaledValue.multiply(powerOfTen).divide( + divisor.unscaledValue); + // To strip trailing zeros aproximating to the preferred scale + while (!integralValue.testBit(0)) { + quotAndRem = integralValue.divideAndRemainder(TEN_POW[i]); + if ((quotAndRem[1].signum() == 0) + && (tempScale - i >= newScale)) { + tempScale -= i; + if (i < lastPow) { + i++; + } + integralValue = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } + newScale = tempScale; + } + return ((integralValue.signum() == 0) ? zeroScaledBy(newScale) + : new BigDecimal(integralValue, toIntScale(newScale))); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) { + int mcPrecision = mc.getPrecision(); + int diffPrecision = this.precision() - divisor.precision(); + int lastPow = TEN_POW.length - 1; + long diffScale = (long) this.scale - divisor.scale; + long newScale = diffScale; + long quotPrecision = diffPrecision - diffScale + 1; + BigInteger quotAndRem[] = new BigInteger[2]; + // In special cases it call the dual method + if ((mcPrecision == 0) || (this.signum() == 0) + || (divisor.signum() == 0)) { + return this.divideToIntegralValue(divisor); + } + // Let be: this = [u1,s1] and divisor = [u2,s2] + if (quotPrecision <= 0) { + quotAndRem[0] = BigInteger.ZERO; + } else if (diffScale == 0) { + // CASE s1 == s2: to calculate u1 / u2 + quotAndRem[0] = this.unscaledValue.divide(divisor.unscaledValue); + } else if (diffScale > 0) { + // CASE s1 >= s2: to calculate u1 / (u2 * 10^(s1-s2) + quotAndRem[0] = this.unscaledValue.divide(divisor.unscaledValue + .multiply(powerOf10(diffScale))); + // To chose 10^newScale to get a quotient with at least 'mc.precision()' digits + newScale = Math.min(diffScale, Math.max((long) mcPrecision + - quotPrecision + 1, 0)); + // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale + quotAndRem[0] = quotAndRem[0].multiply(powerOf10(newScale)); + } else {// CASE s2 > s1: + /* To calculate the minimus power of ten, such that the quotient + * (u1 * 10^exp) / u2 has at least 'mc.precision()' digits. */ + long exp = Math.min(-diffScale, Math.max((long) mcPrecision + - diffPrecision, 0)); + long compRemDiv; + // Let be: (u1 * 10^exp) / u2 = [q,r] + quotAndRem = this.unscaledValue.multiply(powerOf10(exp)) + .divideAndRemainder(divisor.unscaledValue); + newScale += exp; // To fix the scale + exp = -newScale; // The remaining power of ten + // If after division there is a remainder... + if ((quotAndRem[1].signum() != 0) && (exp > 0)) { + // Log10(r) + ((s2 - s1) - exp) > mc.precision ? + compRemDiv = (new BigDecimal(quotAndRem[1])).precision() + exp + - (long) divisor.precision(); + if (compRemDiv == 0) { + // To calculate: (r * 10^exp2) / u2 + quotAndRem[1] = quotAndRem[1].multiply(powerOf10(exp)) + .divide(divisor.unscaledValue); + compRemDiv = Math.abs(quotAndRem[1].signum()); + } + if (compRemDiv > 0) { + // The quotient won't fit in 'mc.precision()' digits + throw new ArithmeticException("Division impossible"); + } + } + } + // Fast return if the quotient is zero + if (quotAndRem[0].signum() == 0) { + return zeroScaledBy(diffScale); + } + BigInteger strippedBI = quotAndRem[0]; + BigDecimal integralValue = new BigDecimal(quotAndRem[0]); + long resultPrecision = integralValue.precision(); + int i = 1; + // To strip trailing zeros until the specified precision is reached + while (!strippedBI.testBit(0)) { + quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]); + if ((quotAndRem[1].signum() == 0) + && ((resultPrecision - i >= mcPrecision) || (newScale - i >= diffScale))) { + resultPrecision -= i; + newScale -= i; + if (i < lastPow) { + i++; + } + strippedBI = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } + // To check if the result fit in 'mc.precision()' digits + if (resultPrecision > mcPrecision) { + throw new ArithmeticException("Division impossible"); + } else { + integralValue.unscaledValue = strippedBI; + integralValue.scale = toIntScale(newScale); + return integralValue; + } + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal remainder(BigDecimal divisor) { + return divideAndRemainder(divisor)[1]; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal remainder(BigDecimal divisor, MathContext mc) { + return divideAndRemainder(divisor, mc)[1]; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal[] divideAndRemainder(BigDecimal divisor) { + BigDecimal quotAndRem[] = new BigDecimal[2]; + + quotAndRem[0] = this.divideToIntegralValue(divisor); + quotAndRem[1] = this.subtract(quotAndRem[0].multiply(divisor)); + return quotAndRem; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc) { + BigDecimal quotAndRem[] = new BigDecimal[2]; + + quotAndRem[0] = this.divideToIntegralValue(divisor, mc); + quotAndRem[1] = this.subtract(quotAndRem[0].multiply(divisor)); + return quotAndRem; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal pow(int n) { + if (n == 0) { + return ONE; + } + if ((n < 0) || (n > 999999999)) { + throw new ArithmeticException("Invalid operation"); + } + long newScale = scale * (long) n; + // Let be: this = [u,s] so: this^n = [u^n, s*n] + return ((signum() == 0) ? zeroScaledBy(newScale) : new BigDecimal( + unscaledValue.pow(n), toIntScale(newScale))); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal pow(int n, MathContext mc) { + // The ANSI standard X3.274-1996 algorithm + int m = Math.abs(n); + int mcPrecision = mc.getPrecision(); + int elength = (int) Math.log10(m) + 1; // decimal digits in 'n' + int oneBitMask; // mask of bits + BigDecimal accum; // the single accumulator + MathContext newPrecision = mc; // MathContext by default + + // In particular cases, it reduces the problem to call the other 'pow()' + if ((n == 0) || ((signum() == 0) && (n > 0))) { + return pow(n); + } + if ((m > 999999999) || ((mcPrecision == 0) && (n < 0)) + || ((mcPrecision > 0) && (elength > mcPrecision))) { + throw new ArithmeticException("Invalid Operation"); + } + if (mcPrecision > 0) { + newPrecision = new MathContext(mcPrecision + elength + 1, mc + .getRoundingMode()); + } + // The result is calculated as if 'n' were positive + accum = round(newPrecision); + oneBitMask = Integer.highestOneBit(m) >> 1; + + while (oneBitMask > 0) { + accum = accum.multiply(accum, newPrecision); + if ((m & oneBitMask) == oneBitMask) { + accum = accum.multiply(this, newPrecision); + } + oneBitMask >>= 1; + } + // If 'n' is negative, the value is divided into 'ONE' + if (n < 0) { + accum = ONE.divide(accum, newPrecision); + } + // The final value is rounded to the destination precision + accum.inplaceRound(mc); + return accum; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal abs() { + return ((signum() < 0) ? negate() : this); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal abs(MathContext mc) { + return round(mc).abs(); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal negate() { + return new BigDecimal(unscaledValue.negate(), scale); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal negate(MathContext mc) { + return round(mc).negate(); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal plus() { + return this; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal plus(MathContext mc) { + return round(mc); + } + + /** @ar.org.fitc.spec_ref */ + public int signum() { + return unscaledValue.signum(); + } + + /** @ar.org.fitc.spec_ref */ + public int scale() { + return scale; + } + + /** @ar.org.fitc.spec_ref */ + public int precision() { + // Checking if the precision already was calculated + if (precision > 0) { + return precision; + } + int bitLength = unscaledValue.bitLength(); + int decimalDigits = 1; // the precision to be calculated + double doubleUnsc = 1; // unscaledValue in 'double' + + if (bitLength < 1024) { + // To calculate the precision for small numbers + if (bitLength >= 64) { + doubleUnsc = unscaledValue.doubleValue(); + } else if (bitLength >= 32) { + doubleUnsc = unscaledValue.longValue(); + } else if (bitLength >= 1) { + doubleUnsc = unscaledValue.intValue(); + } + decimalDigits += Math.log10(Math.abs(doubleUnsc)); + } else {// (bitLength >= 1024) + /* To calculate the precision for large numbers + * Note that: 2 ^(bitlength() - 1) <= unscaledValue < 10 ^(precision()) */ + decimalDigits += (bitLength - 1) * LOG10_2; + // If after division the number isn't zero, exists an aditional digit + if (unscaledValue.divide(powerOf10(decimalDigits)).signum() != 0) { + decimalDigits++; + } + } + precision = decimalDigits; + return precision; + } + + /** @ar.org.fitc.spec_ref */ + public BigInteger unscaledValue() { + return unscaledValue; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal round(MathContext mc) { + BigDecimal thisBD = new BigDecimal(unscaledValue, scale); + + thisBD.inplaceRound(mc); + return thisBD; + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal setScale(int newScale, RoundingMode roundingMode) { + long diffScale = newScale - (long) scale; + + if (roundingMode == null) { + throw new NullPointerException(); + } + // Let be: 'this' = [u,s] + return ((diffScale >= 0) + // return [u * 10^(s2 - s), newScale] + ? new BigDecimal(unscaledValue.multiply(powerOf10(diffScale)), + newScale) + // return [u,s] / [1,newScale] with the apropiate scale and rounding + : this.divide(BigDecimal.ONE, newScale, roundingMode)); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal setScale(int newScale, int roundingMode) { + return setScale(newScale, RoundingMode.valueOf(roundingMode)); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal setScale(int newScale) { + return setScale(newScale, RoundingMode.UNNECESSARY); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal movePointLeft(int n) { + long newScale = scale + (long) n; + + if (signum() == 0) { + return zeroScaledBy(Math.max(newScale, 0)); + } else { + /* When: 'n'== Integer.MIN_VALUE isn't possible to call to movePointRight(-n) + * since -Integer.MIN_VALUE == Integer.MIN_VALUE */ + return ((newScale >= 0) ? new BigDecimal(unscaledValue, + toIntScale(newScale)) : new BigDecimal(unscaledValue + .multiply(powerOf10(-newScale)), 0)); + } + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal movePointRight(int n) { + long newScale = scale - (long) n; + + if (signum() == 0) { + return zeroScaledBy(Math.max(newScale, 0)); + } else { + // Here we have the same observation that in the movePointLeft(int) method + return ((newScale >= 0) ? new BigDecimal(unscaledValue, + toIntScale(newScale)) : new BigDecimal(unscaledValue + .multiply(powerOf10(-newScale)), 0)); + } + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal scaleByPowerOfTen(int n) { + long newScale = scale - (long) n; + + return ((signum() == 0) ? zeroScaledBy(newScale) : new BigDecimal( + unscaledValue, toIntScale(newScale))); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal stripTrailingZeros() { + int i = 1; // 1 <= i <= 18 + int lastPow = TEN_POW.length - 1; + long newScale = scale; + BigInteger strippedBI = unscaledValue; + BigInteger[] quotAndRem; + + if (signum() == 0) { + return this; + } + // while the number is even... + while (!strippedBI.testBit(0)) { + // To divide by 10^i + quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]); + // To look the remainder + if (quotAndRem[1].signum() == 0) { + // To adjust the scale + newScale -= i; + if (i < lastPow) { + // To set to the next power + i++; + } + strippedBI = quotAndRem[0]; + } else { + if (i == 1) { + // 'this' has no more trailing zeros + break; + } + // To set to the smallest power of ten + i = 1; + } + } + return new BigDecimal(strippedBI, toIntScale(newScale)); + } + + /** @ar.org.fitc.spec_ref */ + public int compareTo(BigDecimal val) { + int thisSign = signum(); + + if (thisSign > val.signum()) { + return 1; + } else if (thisSign < val.signum()) { + return -1; + } else {// thisSign == val.signum() + int diffPrecision = this.aproxPrecision() - val.aproxPrecision(); + long diffScale = (long) this.scale - val.scale; + + if (diffPrecision > diffScale + 1) { + return thisSign; + } else if (diffPrecision < diffScale - 1) { + return -thisSign; + } else {// thisSign == val.signum() and diffPrecision is aprox. diffScale + BigInteger thisUnscaled = this.unscaledValue; + BigInteger valUnscaled = val.unscaledValue; + // If any of both precision is bigger, append zeros to the shorter one + if (diffScale < 0) { + thisUnscaled = thisUnscaled.multiply(powerOf10(-diffScale)); + } else if (diffScale > 0) { + valUnscaled = valUnscaled.multiply(powerOf10(diffScale)); + } + return thisUnscaled.compareTo(valUnscaled); + } + } + } + + /** @ar.org.fitc.spec_ref */ + @Override + public boolean equals(Object x) { + return ((x instanceof BigDecimal) && (((BigDecimal) x).scale == scale) && (((BigDecimal) x).unscaledValue + .equals(unscaledValue))); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal min(BigDecimal val) { + return ((compareTo(val) <= 0) ? this : val); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal max(BigDecimal val) { + return ((compareTo(val) >= 0) ? this : val); + } + + /** @ar.org.fitc.spec_ref */ + @Override + public int hashCode() { + /* Take the 24 trailing bits of BigInteger hashcode + * and the 8 trailing bits of scale. */ + return ((unscaledValue.hashCode() << 24) | (0xFF & scale)); + } + + /** @ar.org.fitc.spec_ref */ + @Override + public String toString() { + if (toStringImage != null) { + return toStringImage; + } + String intString = unscaledValue.toString(); + if (scale == 0) { + return intString; + } + int begin = (unscaledValue.signum() < 0) ? 2 : 1; + int end = intString.length(); + long exponent = -(long) scale + end - begin; + StringBuffer result = new StringBuffer(); + + result.append(intString); + if ((scale > 0) && (exponent >= -6)) { + if (exponent >= 0) { + result.insert(end - scale, '.'); + } else { + result.insert(begin - 1, "0."); + result.insert(begin + 1, CH_ZEROS, 0, -(int) exponent - 1); + } + } else { + if (end - begin >= 1) { + result.insert(begin, '.'); + end++; + } + result.insert(end, 'E'); + if (exponent > 0) { + result.insert(++end, '+'); + } + result.insert(++end, Long.toString(exponent)); + } + toStringImage = result.toString(); + return toStringImage; + } + + /** @ar.org.fitc.spec_ref */ + public String toEngineeringString() { + String intString = unscaledValue.toString(); + if (scale == 0) { + return intString; + } + int begin = (unscaledValue.signum() < 0) ? 2 : 1; + int end = intString.length(); + long exponent = -(long) scale + end - begin; + StringBuffer result = new StringBuffer(intString); + + if ((scale > 0) && (exponent >= -6)) { + if (exponent >= 0) { + result.insert(end - scale, '.'); + } else { + result.insert(begin - 1, "0."); + result.insert(begin + 1, CH_ZEROS, 0, -(int) exponent - 1); + } + } else { + int delta = end - begin; + int rem = (int) (exponent % 3); + + if (rem != 0) { + // adjust exponent so it is a multiple of three + if (unscaledValue.signum() == 0) { + // zero value + rem = (rem < 0) ? -rem : 3 - rem; + exponent += rem; + } else { + // nonzero value + rem = (rem < 0) ? rem + 3 : rem; + exponent -= rem; + begin += rem; + } + if (delta < 3) { + for (int i = rem - delta; i > 0; i--) { + result.insert(end++, '0'); + } + System.out.println("1"); + } + } + if (end - begin >= 1) { + result.insert(begin, '.'); + end++; + } + if (exponent != 0) { + result.insert(end, 'E'); + if (exponent > 0) { + result.insert(++end, '+'); + } + result.insert(++end, Long.toString(exponent)); + } + } + return result.toString(); + } + + /** @ar.org.fitc.spec_ref */ + public String toPlainString() { + String intStr = unscaledValue.toString(); + if ((scale == 0) || ((signum() == 0) && (scale < 0))) { + return intStr; + } + int begin = (signum() < 0) ? 1 : 0; + int delta = scale; + // We take space for all digits, plus a possible decimal point, plus 'scale' + StringBuffer result = new StringBuffer(intStr.length() + 1 + + Math.abs(scale)); + + if (begin == 1) { + // If the number is negative, we insert a '-' character at front + result.append('-'); + } + if (scale > 0) { + delta -= (intStr.length() - begin); + if (delta >= 0) { + result.append("0."); + // To append zeros after the decimal point + for (; delta > CH_ZEROS.length; delta -= CH_ZEROS.length) { + result.append(CH_ZEROS); + } + result.append(CH_ZEROS, 0, delta); + result.append(intStr.substring(begin)); + } else { + delta = begin - delta; + result.append(intStr.substring(begin, delta)); + result.append('.'); + result.append(intStr.substring(delta)); + } + } else {// (scale <= 0) + result.append(intStr.substring(begin)); + // To append trailing zeros + for (; delta < -CH_ZEROS.length; delta += CH_ZEROS.length) { + result.append(CH_ZEROS); + } + result.append(CH_ZEROS, 0, -delta); + } + return result.toString(); + } + + /** @ar.org.fitc.spec_ref */ + public BigInteger toBigInteger() { + if ((scale == 0) || (signum() == 0)) { + return unscaledValue; + } else if (scale < 0) { + return unscaledValue.multiply(powerOf10(-(long) scale)); + } else {// (scale > 0) + return unscaledValue.divide(powerOf10(scale)); + } + } + + /** @ar.org.fitc.spec_ref */ + public BigInteger toBigIntegerExact() { + if ((scale == 0) || (signum() == 0)) { + return unscaledValue; + } else if (scale < 0) { + return unscaledValue.multiply(powerOf10(-(long) scale)); + } else {// (scale > 0) + BigInteger[] integerAndFraction; + // An optimization before do a heavy division + if ((scale > aproxPrecision()) + || (scale > unscaledValue.getLowestSetBit())) { + throw new ArithmeticException("Rounding necessary"); + } + integerAndFraction = unscaledValue + .divideAndRemainder(powerOf10(scale)); + if (integerAndFraction[1].signum() != 0) { + // It exists a non-zero fractional part + throw new ArithmeticException("Rounding necessary"); + } else { + return integerAndFraction[0]; + } + } + } + + /** @ar.org.fitc.spec_ref */ + @Override + public long longValue() { + /* If scale <= -64 there are at least 64 trailing bits zero in 10^(-scale). + * If the scale is positive and very large the long value could be zero. */ + return ((scale <= -64) || (scale > aproxPrecision()) ? 0L + : toBigInteger().longValue()); + } + + /** @ar.org.fitc.spec_ref */ + public long longValueExact() { + return valueExact(64); + } + + /** @ar.org.fitc.spec_ref */ + @Override + public int intValue() { + /* If scale <= -32 there are at least 32 trailing bits zero in 10^(-scale). + * If the scale is positive and very large the long value could be zero. */ + return ((scale <= -32) || (scale > aproxPrecision()) ? 0 + : toBigInteger().intValue()); + } + + /** @ar.org.fitc.spec_ref */ + public int intValueExact() { + return (int) valueExact(32); + } + + /** @ar.org.fitc.spec_ref */ + public short shortValueExact() { + return (short) valueExact(16); + } + + /** @ar.org.fitc.spec_ref */ + public byte byteValueExact() { + return (byte) valueExact(8); + } + + /** @ar.org.fitc.spec_ref */ + @Override + public float floatValue() { + /* A similar code like in doubleValue() could be repeated here, + * but this simple implementation is quite efficient. */ + float floatResult = signum(); + long powerOfTwo = unscaledValue.bitLength() - (long) (scale / LOG10_2); + if ((powerOfTwo < -149) || (floatResult == 0.0f)) { + // Cases which 'this' is very small + floatResult *= 0.0f; + } else if (powerOfTwo > 129) { + // Cases which 'this' is very large + floatResult *= Float.POSITIVE_INFINITY; + } else { + floatResult = (float) doubleValue(); + } + return floatResult; + } + + /** @ar.org.fitc.spec_ref */ + @Override + public double doubleValue() { + int sign = signum(); + int exponent = 1076; // bias + 53 + int lowestSetBit; + int discardedSize; + long powerOfTwo = unscaledValue.bitLength() - (long) (scale / LOG10_2); + long bits; // IEEE-754 Standard + long tempBits; // for temporal calculations + BigInteger mantisa; + + if ((powerOfTwo < -1074) || (sign == 0)) { + // Cases which 'this' is very small + return (sign * 0.0d); + } else if (powerOfTwo > 1025) { + // Cases which 'this' is very large + return (sign * Double.POSITIVE_INFINITY); + } + mantisa = unscaledValue.abs(); + // Let be: this = [u,s], with s > 0 + if (scale <= 0) { + // mantisa = abs(u) * 10^s + mantisa = mantisa.multiply(powerOf10(-scale)); + } else {// (scale > 0) + BigInteger quotAndRem[]; + BigInteger powerOfTen = powerOf10(scale); + int k = 100 - (int) powerOfTwo; + int compRem; + + if (k > 0) { + /* Computing (mantisa * 2^k) , where 'k' is a enough big + * power of '2' to can divide by 10^s */ + mantisa = mantisa.shiftLeft(k); + exponent -= k; + } + // Computing (mantisa * 2^k) / 10^s + quotAndRem = mantisa.divideAndRemainder(powerOfTen); + // To check if the fractional part >= 0.5 + compRem = quotAndRem[1].shiftLeft(1).compareTo(powerOfTen); + // To add two rounded bits at end of mantisa + mantisa = quotAndRem[0].shiftLeft(2).add( + BigInteger.valueOf((compRem * (compRem + 3)) / 2 + 1)); + exponent -= 2; + } + lowestSetBit = mantisa.getLowestSetBit(); + discardedSize = mantisa.bitLength() - 54; + if (discardedSize > 0) {// (n > 54) + // mantisa = (abs(u) * 10^s) >> (n - 54) + bits = mantisa.shiftRight(discardedSize).longValue(); + tempBits = bits; + // #bits = 54, to check if the discarded fraction produces a carry + if ((((bits & 1) == 1) && (lowestSetBit < discardedSize)) + || ((bits & 3) == 3)) { + bits += 2; + } + } else {// (n <= 54) + // mantisa = (abs(u) * 10^s) << (54 - n) + bits = mantisa.longValue() << -discardedSize; + tempBits = bits; + // #bits = 54, to check if the discarded fraction produces a carry: + if ((bits & 3) == 3) { + bits += 2; + } + } + // Testing bit 54 to check if the carry creates a new binary digit + if ((bits & 0x40000000000000L) == 0) { + // To drop the last bit of mantisa (first discarded) + bits >>= 1; + // exponent = 2^(s-n+53+bias) + exponent += discardedSize; + } else {// #bits = 54 + bits >>= 2; + exponent += discardedSize + 1; + } + // To test if the 53-bits number fits in 'double' + if (exponent > 2046) {// (exponent - bias > 1023) + return (sign * Double.POSITIVE_INFINITY); + } else if (exponent <= 0) {// (exponent - bias <= -1023) + // Denormalized numbers (having exponent == 0) + if (exponent < -53) {// exponent - bias < -1076 + return (sign * 0.0d); + } else {// -1076 <= exponent - bias <= -1023 + // To discard '- exponent + 1' bits + bits = tempBits >> 1; + tempBits = bits & (-1L >>> (63 + exponent)); + bits >>= (-exponent); + // To test if after discard bits, a new carry is generated + if (((bits & 3) == 3) + || (((bits & 1) == 1) && (tempBits != 0) && (lowestSetBit < discardedSize))) { + bits += 1; + } + exponent = 0; + bits >>= 1; + } + } + // Construct the 64 double bits: [sign(1), exponent(11), mantisa(52)] + bits = (sign & 0x8000000000000000L) | ((long) exponent << 52) + | (bits & 0xFFFFFFFFFFFFFL); + return Double.longBitsToDouble(bits); + } + + /** @ar.org.fitc.spec_ref */ + public BigDecimal ulp() { + return new BigDecimal(BigInteger.ONE, scale); + } + + /* Private Methods */ + + /** + * It does all rounding work of the public method round(MathContext), + * performing an inplace rounding without creating a new object. + * @param mc the MathContext for perform the rounding. + * @see #round(MathContext). + */ + private void inplaceRound(MathContext mc) { + int mcPrecision = mc.getPrecision(); + int discardedPrecision = precision() - mcPrecision; + // If no rounding is necessary it returns inmediatly + if ((discardedPrecision <= 0) || (mcPrecision == 0)) { + return; + } + // When the number is small perform an efficient rounding + if (unscaledValue.bitLength() < 64) { + smallRound(mc, discardedPrecision); + return; + } + // Getting the interger part and the discarded fraction + BigInteger sizeOfFraction = powerOf10(discardedPrecision); + BigInteger[] integerAndFraction = unscaledValue + .divideAndRemainder(sizeOfFraction); + long newScale = (long) scale - discardedPrecision; + int compRem; + BigDecimal tempBD; + // If the discarded fraction is non-zero, perform rounding + if (integerAndFraction[1].signum() != 0) { + // To check if the discarded fraction >= 0.5 + compRem = (integerAndFraction[1].abs().shiftLeft(1) + .compareTo(sizeOfFraction)); + // To look if there is a carry + compRem = roundingBehavior( + integerAndFraction[0].testBit(0) ? 1 : 0, + integerAndFraction[1].signum() * (5 + compRem), mc + .getRoundingMode()); + if (compRem != 0) { + integerAndFraction[0] = integerAndFraction[0].add(BigInteger + .valueOf(compRem)); + } + tempBD = new BigDecimal(integerAndFraction[0]); + // If after to add the increment the precision changed, we normalize the size + if (tempBD.precision() > mcPrecision) { + integerAndFraction[0] = integerAndFraction[0] + .divide(BigInteger.TEN); + newScale--; + } + } + // To update all inernal fields + scale = toIntScale(newScale); + unscaledValue = integerAndFraction[0]; + precision = mcPrecision; + } + + /** + * This method implements an efficient rounding for numbers which unscaled + * value fits in the type long. + * @param mc the context to use. + * @param discardedPrecision the number of decimal digits that are discarded. + * @see #round(MathContext). + */ + private void smallRound(MathContext mc, int discardedPrecision) { + long sizeOfFraction = TEN_POW[discardedPrecision].longValue(); + long newScale = (long) scale - discardedPrecision; + long unscaledVal = unscaledValue.longValue(); + // Getting the interger part and the discarded fraction + long integer = unscaledVal / sizeOfFraction; + long fraction = unscaledVal % sizeOfFraction; + int compRem; + // If the discarded fraction is non-zero perform rounding + if (fraction != 0) { + // To check if the discarded fraction >= 0.5 + compRem = ((new Long(Math.abs(fraction) << 1)) + .compareTo(sizeOfFraction)); + // To look if there is a carry + integer += roundingBehavior(((int) integer) & 1, Long + .signum(fraction) + * (5 + compRem), mc.getRoundingMode()); + // If after to add the increment the precision changed, we normalize the size + if (Math.log10(Math.abs(integer)) >= mc.getPrecision()) { + integer /= 10; + newScale--; + } + } + // To update all inernal fields + scale = toIntScale(newScale); + unscaledValue = BigInteger.valueOf(integer); + precision = mc.getPrecision(); + } + + /** + * Return an increment that can be -1,0 or 1, depending of roundingMode. + * @param parityBit can be 0 or 1, it's only used in the case HALF_EVEN. + * @param fraction the mantisa to be analized. + * @param roundingMode the type of rounding. + * @return the carry propagated after rounding. + */ + private static int roundingBehavior(int parityBit, int fraction, + RoundingMode roundingMode) { + int increment = 0; // the carry after rounding + + switch (roundingMode) { + case UNNECESSARY: + if (fraction != 0) { + throw new ArithmeticException("Rounding necessary"); + } + break; + case UP: + increment = Integer.signum(fraction); + break; + case DOWN: + break; + case CEILING: + increment = Math.max(Integer.signum(fraction), 0); + break; + case FLOOR: + increment = Math.min(Integer.signum(fraction), 0); + break; + case HALF_UP: + if (Math.abs(fraction) >= 5) { + increment = Integer.signum(fraction); + } + break; + case HALF_DOWN: + if (Math.abs(fraction) > 5) { + increment = Integer.signum(fraction); + } + break; + case HALF_EVEN: + if (Math.abs(fraction) + parityBit > 5) { + increment = Integer.signum(fraction); + } + break; + } + return increment; + } + + /** + * If unscaledValue has a fractional part throws an exception, + * otherwise it counts the number of bits of value and checks if it's out + * of the range of the primitive type. If the number fits in the primitive + * type returns this number as long, otherwise throws an + * exception. + * @param bitLengthOfType number of bits of the type whose value will be + * calculated exactly. + * @return the exact value of the integer part of BigDecimal + * when is possible. + * @throws ArithmeticException when rounding is necessary or + * the number don't fit in the primitive type. + */ + private long valueExact(int bitLengthOfType) { + BigInteger bigInteger = toBigIntegerExact(); + + if (bigInteger.bitLength() < bitLengthOfType) { + // It fits in the primitive type + return bigInteger.longValue(); + } else { + throw new ArithmeticException("Rounding necessary"); + } + } + + /** + * If the precion already was calculated it returns that value, otherwise + * it calculates a very good aproximization efficiently . Note that this + * value will be precision() or precision()-1 + * in the worst case. + * @return an aproximization of precision() value + */ + private int aproxPrecision() { + return ((precision > 0) ? precision + : (int) ((unscaledValue.bitLength() - 1) * LOG10_2)) + 1; + } + + /** + * It calculates a power of ten, which exponent could be out of 32-bit range. + * Note that internally this method will be used in the worst case with + * an exponent equals to: Integer.MAX_VALUE - Integer.MIN_VALUE. + * @param exp the exponent of power of ten, it must be positive. + * @return a BigInteger with value 10^exp. + */ + private static BigInteger powerOf10(long exp) { + // PRE: exp >= 0 + int intExp = (int) exp; + // "SMALL POWERS" + if (exp < TEN_POW.length) { + // The largest power that fit in 'long' type + return TEN_POW[intExp]; + } else if (exp <= 50) { + // To calculate: 10^exp + return BigInteger.TEN.pow(intExp); + } else if (exp <= 1000) { + // To calculate: 5^exp * 2^exp + return FIVE_POW[1].pow(intExp).shiftLeft(intExp); + } + // "LARGE POWERS" + /* To check if there is free memory to allocate a BigInteger + * of the estimated size (measured in bytes) */ + long byteArraySize = 1 + (long) (exp / (8 * LOG10_2)); + + if (byteArraySize > Runtime.getRuntime().freeMemory()) { + throw new OutOfMemoryError("power of ten too big"); + } + if (exp <= Integer.MAX_VALUE) { + // To calculate: 5^exp * 2^exp + return FIVE_POW[1].pow(intExp).shiftLeft(intExp); + } else {/* "HUGE POWERS" + * Probably this branch won't be executed + * since the power of ten is too big. */ + // To calculate: 5^exp + BigInteger powerOfFive = FIVE_POW[1].pow(Integer.MAX_VALUE); + BigInteger res = powerOfFive; + long longExp = exp - Integer.MAX_VALUE; + + intExp = (int) (exp % Integer.MAX_VALUE); + while (longExp > Integer.MAX_VALUE) { + res = res.multiply(powerOfFive); + longExp -= Integer.MAX_VALUE; + } + res = res.multiply(FIVE_POW[1].pow(intExp)); + // To calculate: 5^exp << exp + res = res.shiftLeft(Integer.MAX_VALUE); + longExp = exp - Integer.MAX_VALUE; + while (longExp > Integer.MAX_VALUE) { + res = res.shiftLeft(Integer.MAX_VALUE); + longExp -= Integer.MAX_VALUE; + } + res = res.shiftLeft(intExp); + return res; + } + } + + /** + * It tests if a scale of type long fits in 32 bits. + * It returns the same scale being casted to int type when + * is possible, otherwise throws an exception. + * @param longScale a 64 bit scale. + * @return a 32 bit scale when is possible. + * @throws ArithmeticException when scale + * doesn't fit in int type. + * @see #scale + */ + private static int toIntScale(long longScale) { + if (longScale < Integer.MIN_VALUE) { + throw new ArithmeticException("Overflow"); + } else if (longScale > Integer.MAX_VALUE) { + throw new ArithmeticException("Underflow"); + } else { + return (int) longScale; + } + } + + /** + * It returns the value 0 with the most aproximated scale of type + * int. if longScale > Integer.MAX_VALUE + * the scale will be Integer.MAX_VALUE; if + * longScale < Integer.MIN_VALUE the scale will be + * Integer.MIN_VALUE; otherwise longScale is + * casted to the type int. + * @param longScale the scale to which the value 0 will be scaled. + * @return the value 0 scaled by the closer scale of type int. + * @see #scale + */ + private static BigDecimal zeroScaledBy(long longScale) { + if (longScale >= 0) { + if (longScale < ZERO_SCALED_BY.length) { + return ZERO_SCALED_BY[(int) longScale]; + } else { + return new BigDecimal(BigInteger.ZERO, + (longScale <= Integer.MAX_VALUE) ? (int) longScale + : Integer.MAX_VALUE); + } + } else { + return new BigDecimal(BigInteger.ZERO, + (longScale >= Integer.MIN_VALUE) ? (int) longScale + : Integer.MIN_VALUE); + } + } + + /** @ar.org.fitc.spec_ref */ + private void readObject(ObjectInputStream in) throws IOException, + ClassNotFoundException { + in.defaultReadObject(); + if (unscaledValue == null) { + throw new StreamCorruptedException("null unscaled value"); + } + } + +} Propchange: incubator/harmony/enhanced/classlib/trunk/modules/math/src/main/java/java/math/BigDecimal.java ------------------------------------------------------------------------------ svn:executable = *