/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* * Imported from Apache Harmony CG 20060208, based on revision 566500. * Stripped down to 1.4 API. * I have reverted the TLS stuff to hard-coded strings. */ package java.math; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @author Intel Middleware Product Division * @author Instituto Tecnologico de Cordoba */ public class BigDecimal extends Number implements Comparable, Serializable { /* Static Fields */ /** ** [CG 20080209] Constant only defined since 1.5, so we make it private. ** We don't define ZERO or TEN because we don't use them internally either. */ private static final BigDecimal ONE = new BigDecimal(1, 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; /* Private Fields */ private static final long serialVersionUID = 6108874887143696463L; /** The double closer to <code>Log10(2)</code>. */ private static final double LOG10_2 = 0.3010299956639812; /** The <code>String</code> representation is cached. */ private transient String toStringImage = null; private transient int hashCode = 0; /** * An array with powers of five that fit in the type <code>long</code> * (<code>5^0,5^1,...,5^27</code>) */ private static final BigInteger FIVE_POW[]; /** * An array with powers of ten that fit in the type <code>long</code> * (<code>10^0,10^1,...,10^18</code>) */ private static final BigInteger TEN_POW[]; /** * An array with powers of ten that fit in the type <code>long</code> * (<code>10^0,10^1,...,10^18</code>) */ private static final long[] LONG_TEN_POW = new long[] { 1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L, 1000000000L, 10000000000L, 100000000000L, 1000000000000L, 10000000000000L, 100000000000000L, 1000000000000000L, 10000000000000000L, 100000000000000000L, 1000000000000000000L, }; private static final long[] LONG_FIVE_POW = new long[] { 1L, 5L, 25L, 125L, 625L, 3125L, 15625L, 78125L, 390625L, 1953125L, 9765625L, 48828125L, 244140625L, 1220703125L, 6103515625L, 30517578125L, 152587890625L, 762939453125L, 3814697265625L, 19073486328125L, 95367431640625L, 476837158203125L, 2384185791015625L, 11920928955078125L, 59604644775390625L, 298023223876953125L, 1490116119384765625L, 7450580596923828125L, }; private static final int[] LONG_FIVE_POW_BIT_LENGTH = new int[LONG_FIVE_POW.length]; private static final int[] LONG_TEN_POW_BIT_LENGTH = new int[LONG_TEN_POW.length]; private static final int BI_SCALED_BY_ZERO_LENGTH = 11; /** * An array with the first <code>BigInteger</code> scaled by zero. * (<code>[0,0],[1,0],...,[10,0]</code>) */ private static final BigDecimal BI_SCALED_BY_ZERO[] = new BigDecimal[BI_SCALED_BY_ZERO_LENGTH]; /** * An array with the zero number scaled by the first positive scales. * (<code>0*10^0, 0*10^1, ..., 0*10^10</code>) */ private static final BigDecimal ZERO_SCALED_BY[] = new BigDecimal[11]; /** An array filled with characters <code>'0'</code>. */ private static final char[] CH_ZEROS = new char[100]; static { // To fill all static arrays. int i = 0; for (; i < ZERO_SCALED_BY.length; i++) { BI_SCALED_BY_ZERO[i] = new BigDecimal(i, 0); ZERO_SCALED_BY[i] = new BigDecimal(0, i); CH_ZEROS[i] = '0'; } for (; i < CH_ZEROS.length; i++) { CH_ZEROS[i] = '0'; } for(int j=0; j<LONG_FIVE_POW_BIT_LENGTH.length; j++) { LONG_FIVE_POW_BIT_LENGTH[j] = bitLength(LONG_FIVE_POW[j]); } for(int j=0; j<LONG_TEN_POW_BIT_LENGTH.length; j++) { LONG_TEN_POW_BIT_LENGTH[j] = bitLength(LONG_TEN_POW[j]); } // Taking the references of useful powers. TEN_POW = Multiplication.bigTenPows; FIVE_POW = Multiplication.bigFivePows; } /** * The arbitrary precision integer (unscaled value) in the internal * representation of <code>BigDecimal</code>. */ private BigInteger intVal; private transient int bitLength; private transient long smallValue; /** * The 32-bit integer scale in the internal representation of <code>BigDecimal</code>. */ 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 <code>precision()</code>. */ private transient int precision = 0; /* Constructors */ private BigDecimal(long smallValue, int scale){ this.smallValue = smallValue; this.scale = scale; this.bitLength = bitLength(smallValue); } private BigDecimal(int smallValue, int scale){ this.smallValue = smallValue; this.scale = scale; this.bitLength = bitLength(smallValue); } /** ** [CG 20080209] Constructor only defined since 1.5, so we make it private. */ private 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); int bufLength = 0; // To skip a possible '+' symbol if ((offset <= last) && (in[offset] == '+')) { offset++; begin++; } int counter = 0; boolean wasNonZero = false; // Accumulating all digits until a possible decimal point for (; (offset <= last) && (in[offset] != '.') && (in[offset] != 'e') && (in[offset] != 'E'); offset++) { if (!wasNonZero) { if (in[offset] == '0') { counter++; } else { wasNonZero = true; } }; } unscaledBuffer.append(in, begin, offset - begin); bufLength += offset - begin; // A decimal point was found if ((offset <= last) && (in[offset] == '.')) { offset++; // Accumulating all digits until a possible exponent begin = offset; for (; (offset <= last) && (in[offset] != 'e') && (in[offset] != 'E'); offset++) { if (!wasNonZero) { if (in[offset] == '0') { counter++; } else { wasNonZero = true; } }; } scale = offset - begin; bufLength +=scale; 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 possible sign of scale begin = offset; if ((offset <= last) && (in[offset] == '+')) { offset++; if ((offset <= last) && (in[offset] != '-')) { begin++; } } // Accumulating all remaining 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 if (bufLength < 19) { smallValue = Long.parseLong(unscaledBuffer.toString()); bitLength = bitLength(smallValue); } else { setUnscaledValue(new BigInteger(unscaledBuffer.toString())); } precision = unscaledBuffer.length() - counter; if (unscaledBuffer.charAt(0) == '-') { precision --; } } public BigDecimal(String val) { this(val.toCharArray(), 0, val.length()); } public BigDecimal(double val) { if (Double.isInfinite(val) || Double.isNaN(val)) { throw new NumberFormatException("Infinity 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; if (mantisa == 0) { scale = 0; precision = 1; } // To simplify all factors '2' in the mantisa if (scale > 0) { trailingZeros = Math.min(scale, Utils.numberOfTrailingZeros(mantisa)); mantisa >>>= trailingZeros; scale -= trailingZeros; } // Calculating the new unscaled value and the new scale if((bits >> 63) != 0) { mantisa = -mantisa; } int mantisaBits = bitLength(mantisa); if (scale < 0) { bitLength = mantisaBits == 0 ? 0 : mantisaBits - scale; if(bitLength < 64) { smallValue = mantisa << (-scale); } else { intVal = BigInteger.valueOf(mantisa).shiftLeft(-scale); } scale = 0; } else if (scale > 0) { // m * 2^e = (m * 5^(-e)) * 10^e if(scale < LONG_FIVE_POW.length && mantisaBits+LONG_FIVE_POW_BIT_LENGTH[scale] < 64) { smallValue = mantisa * LONG_FIVE_POW[scale]; bitLength = bitLength(smallValue); } else { setUnscaledValue(Multiplication.multiplyByFivePow(BigInteger.valueOf(mantisa), scale)); } } else { // scale == 0 smallValue = mantisa; bitLength = mantisaBits; } } public BigDecimal(BigInteger val) { this(val, 0); } public BigDecimal(BigInteger unscaledVal, int scale) { if (unscaledVal == null) { throw new NullPointerException(); } this.scale = scale; setUnscaledValue(unscaledVal); } public BigDecimal(int val) { this(val,0); } /* Public Methods */ public static BigDecimal valueOf(long unscaledVal, int scale) { if (scale == 0) { return valueOf(unscaledVal); } if ((unscaledVal == 0) && (scale >= 0) && (scale < ZERO_SCALED_BY.length)) { return ZERO_SCALED_BY[scale]; } return new BigDecimal(unscaledVal, scale); } public static BigDecimal valueOf(long unscaledVal) { if ((unscaledVal >= 0) && (unscaledVal < BI_SCALED_BY_ZERO_LENGTH)) { return BI_SCALED_BY_ZERO[(int)unscaledVal]; } return new BigDecimal(unscaledVal,0); } public BigDecimal add(BigDecimal augend) { int diffScale = this.scale - augend.scale; // Fast return when some operand is zero if (this.isZero()) { if (diffScale <= 0) { return augend; } if (augend.isZero()) { return this; } } else if (augend.isZero()) { if (diffScale >= 0) { return this; } } // Let be: this = [u1,s1] and augend = [u2,s2] if (diffScale == 0) { // case s1 == s2: [u1 + u2 , s1] if (Math.max(this.bitLength, augend.bitLength) + 1 < 64) { return valueOf(this.smallValue + augend.smallValue, this.scale); } return new BigDecimal(this.getUnscaledValue().add(augend.getUnscaledValue()), this.scale); } else if (diffScale > 0) { // case s1 > s2 : [(u1 + u2) * 10 ^ (s1 - s2) , s1] return addAndMult10(this, augend, diffScale); } else {// case s2 > s1 : [(u2 + u1) * 10 ^ (s2 - s1) , s2] return addAndMult10(augend, this, -diffScale); } } private static BigDecimal addAndMult10(BigDecimal thisValue,BigDecimal augend, int diffScale) { if(diffScale < LONG_TEN_POW.length && Math.max(thisValue.bitLength,augend.bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) { return valueOf(thisValue.smallValue+augend.smallValue*LONG_TEN_POW[diffScale],thisValue.scale); } return new BigDecimal(thisValue.getUnscaledValue().add( Multiplication.multiplyByTenPow(augend.getUnscaledValue(),diffScale)), thisValue.scale); } public BigDecimal subtract(BigDecimal subtrahend) { int diffScale = this.scale - subtrahend.scale; // Fast return when some operand is zero if (this.isZero()) { if (diffScale <= 0) { return subtrahend.negate(); } if (subtrahend.isZero()) { return this; } } else if (subtrahend.isZero()) { if (diffScale >= 0) { return this; } } // Let be: this = [u1,s1] and subtrahend = [u2,s2] so: if (diffScale == 0) { // case s1 = s2 : [u1 - u2 , s1] if (Math.max(this.bitLength, subtrahend.bitLength) + 1 < 64) { return valueOf(this.smallValue - subtrahend.smallValue,this.scale); } return new BigDecimal(this.getUnscaledValue().subtract(subtrahend.getUnscaledValue()), this.scale); } else if (diffScale > 0) { // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ] if(diffScale < LONG_TEN_POW.length && Math.max(this.bitLength,subtrahend.bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) { return valueOf(this.smallValue-subtrahend.smallValue*LONG_TEN_POW[diffScale],this.scale); } return new BigDecimal(this.getUnscaledValue().subtract( Multiplication.multiplyByTenPow(subtrahend.getUnscaledValue(),diffScale)), this.scale); } else {// case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ] diffScale = -diffScale; if(diffScale < LONG_TEN_POW.length && Math.max(this.bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale],subtrahend.bitLength)+1<64) { return valueOf(this.smallValue*LONG_TEN_POW[diffScale]-subtrahend.smallValue,subtrahend.scale); } return new BigDecimal(Multiplication.multiplyByTenPow(this.getUnscaledValue(),diffScale) .subtract(subtrahend.getUnscaledValue()), subtrahend.scale); } } public BigDecimal multiply(BigDecimal multiplicand) { long newScale = (long)this.scale + multiplicand.scale; if ((this.isZero()) || (multiplicand.isZero())) { return zeroScaledBy(newScale); } /* Let be: this = [u1,s1] and multiplicand = [u2,s2] so: * this x multiplicand = [ s1 * s2 , s1 + s2 ] */ if(this.bitLength + multiplicand.bitLength < 64) { return valueOf(this.smallValue*multiplicand.smallValue,toIntScale(newScale)); } return new BigDecimal(this.getUnscaledValue().multiply( multiplicand.getUnscaledValue()), toIntScale(newScale)); } public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) { // Let be: this = [u1,s1] and divisor = [u2,s2] if (divisor.isZero()) { throw new ArithmeticException("Division by zero"); } if (roundingMode < 0 || roundingMode > 7) { throw new IllegalArgumentException("Illegal rounding mode"); } long diffScale = ((long)this.scale - divisor.scale) - scale; if(this.bitLength < 64 && divisor.bitLength < 64 ) { if(diffScale == 0) { return dividePrimitiveLongs(this.smallValue, divisor.smallValue, scale, roundingMode ); } else if(diffScale > 0) { if(diffScale < LONG_TEN_POW.length && divisor.bitLength + LONG_TEN_POW_BIT_LENGTH[(int)diffScale] < 64) { return dividePrimitiveLongs(this.smallValue, divisor.smallValue*LONG_TEN_POW[(int)diffScale], scale, roundingMode); } } else { // diffScale < 0 if(-diffScale < LONG_TEN_POW.length && this.bitLength + LONG_TEN_POW_BIT_LENGTH[(int)-diffScale] < 64) { return dividePrimitiveLongs(this.smallValue*LONG_TEN_POW[(int)-diffScale], divisor.smallValue, scale, roundingMode); } } } BigInteger scaledDividend = this.getUnscaledValue(); BigInteger scaledDivisor = divisor.getUnscaledValue(); // for scaling of 'u2' if (diffScale > 0) { // Multiply 'u2' by: 10^((s1 - s2) - scale) scaledDivisor = Multiplication.multiplyByTenPow(scaledDivisor, (int)diffScale); } else if (diffScale < 0) { // Multiply 'u1' by: 10^(scale - (s1 - s2)) scaledDividend = Multiplication.multiplyByTenPow(scaledDividend, (int)-diffScale); } return divideBigIntegers(scaledDividend, scaledDivisor, scale, roundingMode); } private static BigDecimal divideBigIntegers(BigInteger scaledDividend, BigInteger scaledDivisor, int scale, int roundingMode) { BigInteger[] quotAndRem = scaledDividend.divideAndRemainder(scaledDivisor); // quotient and remainder // If after division there is a remainder... BigInteger quotient = quotAndRem[0]; BigInteger remainder = quotAndRem[1]; if (remainder.signum() == 0) { return new BigDecimal(quotient, scale); } int sign = scaledDividend.signum() * scaledDivisor.signum(); int compRem; // 'compare to remainder' if(scaledDivisor.bitLength() < 63) { // 63 in order to avoid out of long after <<1 long rem = remainder.longValue(); long divisor = scaledDivisor.longValue(); compRem = longCompareTo(Math.abs(rem) << 1,Math.abs(divisor)); // To look if there is a carry compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0, sign * (5 + compRem), roundingMode); } else { // Checking if: remainder * 2 >= scaledDivisor compRem = remainder.abs().shiftLeft(1).compareTo(scaledDivisor.abs()); compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0, sign * (5 + compRem), roundingMode); } if (compRem != 0) { if(quotient.bitLength() < 63) { return valueOf(quotient.longValue() + compRem,scale); } quotient = quotient.add(BigInteger.valueOf(compRem)); return new BigDecimal(quotient, scale); } // Constructing the result with the appropriate unscaled value return new BigDecimal(quotient, scale); } private static BigDecimal dividePrimitiveLongs(long scaledDividend, long scaledDivisor, int scale, int roundingMode) { long quotient = scaledDividend / scaledDivisor; long remainder = scaledDividend % scaledDivisor; int sign = Utils.signum( scaledDividend ) * Utils.signum( scaledDivisor ); if (remainder != 0) { // Checking if: remainder * 2 >= scaledDivisor int compRem; // 'compare to remainder' compRem = longCompareTo(Math.abs(remainder) << 1,Math.abs(scaledDivisor)); // To look if there is a carry quotient += roundingBehavior(((int)quotient) & 1, sign * (5 + compRem), roundingMode); } // Constructing the result with the appropriate unscaled value return valueOf(quotient, scale); } public BigDecimal divide(BigDecimal divisor, int roundingMode) { return divide(divisor, scale, roundingMode); } public BigDecimal divide(BigDecimal divisor) { BigInteger p = this.getUnscaledValue(); BigInteger q = divisor.getUnscaledValue(); 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.isZero()) { throw new ArithmeticException("Division 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"); } // 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 > 0) ? Multiplication.multiplyByFivePow(p, i) : p.shiftLeft(-i); return new BigDecimal(p, newScale); } 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 ((isZero()) ? zeroScaledBy(newScale) : new BigDecimal(getUnscaledValue().pow(n), toIntScale(newScale))); } public BigDecimal abs() { return ((signum() < 0) ? negate() : this); } public BigDecimal negate() { if(bitLength < 63 || (bitLength == 63 && smallValue!=Long.MIN_VALUE)) { return valueOf(-smallValue,scale); } return new BigDecimal(getUnscaledValue().negate(), scale); } public int signum() { if( bitLength < 64) { return Utils.signum( this.smallValue ); } return getUnscaledValue().signum(); } private boolean isZero() { //Watch out: -1 has a bitLength=0 return bitLength == 0 && this.smallValue != -1; } public int scale() { return scale; } public BigInteger unscaledValue() { return getUnscaledValue(); } public BigDecimal setScale(int newScale, int roundingMode) { long diffScale = newScale - (long)scale; // Let be: 'this' = [u,s] if(diffScale == 0) { return this; } if(diffScale > 0) { // return [u * 10^(s2 - s), newScale] if(diffScale < LONG_TEN_POW.length && (this.bitLength + LONG_TEN_POW_BIT_LENGTH[(int)diffScale]) < 64 ) { return valueOf(this.smallValue*LONG_TEN_POW[(int)diffScale],newScale); } return new BigDecimal(Multiplication.multiplyByTenPow(getUnscaledValue(),(int)diffScale), newScale); } // diffScale < 0 // return [u,s] / [1,newScale] with the appropriate scale and rounding if(this.bitLength < 64 && -diffScale < LONG_TEN_POW.length) { return dividePrimitiveLongs(this.smallValue, LONG_TEN_POW[(int)-diffScale], newScale,roundingMode); } return divideBigIntegers(this.getUnscaledValue(),Multiplication.powerOf10(-diffScale),newScale,roundingMode); } public BigDecimal setScale(int newScale) { return setScale(newScale, ROUND_UNNECESSARY); } public BigDecimal movePointLeft(int n) { return movePoint(scale + (long)n); } private BigDecimal movePoint(long newScale) { if (isZero()) { return zeroScaledBy(Math.max(newScale, 0)); } /* When: 'n'== Integer.MIN_VALUE isn't possible to call to movePointRight(-n) * since -Integer.MIN_VALUE == Integer.MIN_VALUE */ if(newScale >= 0) { if(bitLength < 64) { return valueOf(smallValue,toIntScale(newScale)); } return new BigDecimal(getUnscaledValue(), toIntScale(newScale)); } if(-newScale < LONG_TEN_POW.length && bitLength + LONG_TEN_POW_BIT_LENGTH[(int)-newScale] < 64 ) { return valueOf(smallValue*LONG_TEN_POW[(int)-newScale],0); } return new BigDecimal(Multiplication.multiplyByTenPow(getUnscaledValue(),(int)-newScale), 0); } public BigDecimal movePointRight(int n) { return movePoint(scale - (long)n); } public int compareTo(Object o) throws ClassCastException { return compareTo((BigDecimal)o); } public int compareTo(BigDecimal val) { int thisSign = signum(); int valueSign = val.signum(); if( thisSign == valueSign) { if(this.scale == val.scale && this.bitLength<64 && val.bitLength<64 ) { return (smallValue < val.smallValue) ? -1 : (smallValue > val.smallValue) ? 1 : 0; } long diffScale = (long)this.scale - val.scale; int diffPrecision = this.aproxPrecision() - val.aproxPrecision(); 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.getUnscaledValue(); BigInteger valUnscaled = val.getUnscaledValue(); // If any of both precision is bigger, append zeros to the shorter one if (diffScale < 0) { thisUnscaled = thisUnscaled.multiply(Multiplication.powerOf10(-diffScale)); } else if (diffScale > 0) { valUnscaled = valUnscaled.multiply(Multiplication.powerOf10(diffScale)); } return thisUnscaled.compareTo(valUnscaled); } } else if (thisSign < valueSign) { return -1; } else { return 1; } } public boolean equals(Object x) { if (this == x) { return true; } if (x instanceof BigDecimal) { BigDecimal x1 = (BigDecimal) x; return x1.scale == scale && (bitLength < 64 ? (x1.smallValue == smallValue) : intVal.equals(x1.intVal)); } return false; } public BigDecimal min(BigDecimal val) { return ((compareTo(val) <= 0) ? this : val); } public BigDecimal max(BigDecimal val) { return ((compareTo(val) >= 0) ? this : val); } public int hashCode() { if (hashCode != 0) { return hashCode; } if (bitLength < 64) { hashCode = (int)(smallValue & 0xffffffff); hashCode = 33 * hashCode + (int)((smallValue >> 32) & 0xffffffff); hashCode = 17 * hashCode + scale; return hashCode; } hashCode = 17 * intVal.hashCode() + scale; return hashCode; } public String toString() { if (toStringImage != null) { return toStringImage; } if(bitLength < 32) { toStringImage = Conversion.toDecimalScaledString(smallValue,scale); return toStringImage; } String intString = getUnscaledValue().toString(); if (scale == 0) { return intString; } int begin = (getUnscaledValue().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."); //$NON-NLS-1$ 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; } public BigInteger toBigInteger() { if ((scale == 0) || (isZero())) { return getUnscaledValue(); } else if (scale < 0) { return getUnscaledValue().multiply(Multiplication.powerOf10(-(long)scale)); } else {// (scale > 0) return getUnscaledValue().divide(Multiplication.powerOf10(scale)); } } 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()); } 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()); } 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 = this.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; } public double doubleValue() { int sign = signum(); int exponent = 1076; // bias + 53 int lowestSetBit; int discardedSize; long powerOfTwo = this.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 = getUnscaledValue().abs(); // Let be: this = [u,s], with s > 0 if (scale <= 0) { // mantisa = abs(u) * 10^s mantisa = mantisa.multiply(Multiplication.powerOf10(-scale)); } else {// (scale > 0) BigInteger quotAndRem[]; BigInteger powerOfTen = Multiplication.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); } // -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); } /* Private Methods */ private static int longCompareTo(long value1, long value2) { return value1 > value2 ? 1 : (value1 < value2 ? -1 : 0); } /** * Return an increment that can be -1,0 or 1, depending of <code>roundingMode</code>. * @param parityBit can be 0 or 1, it's only used in the case <code>HALF_EVEN</code>. * @param fraction the mantisa to be analyzed. * @param roundingMode the type of rounding. * @return the carry propagated after rounding. */ private static int roundingBehavior(int parityBit, int fraction, int roundingMode) { int increment = 0; // the carry after rounding switch (roundingMode) { case ROUND_UNNECESSARY: if (fraction != 0) { // math.08=Rounding necessary throw new ArithmeticException("Rounding necessary"); } break; case ROUND_UP: increment = Utils.signum(fraction); break; case ROUND_DOWN: break; case ROUND_CEILING: increment = Math.max(Utils.signum(fraction), 0); break; case ROUND_FLOOR: increment = Math.min(Utils.signum(fraction), 0); break; case ROUND_HALF_UP: if (Math.abs(fraction) >= 5) { increment = Utils.signum(fraction); } break; case ROUND_HALF_DOWN: if (Math.abs(fraction) > 5) { increment = Utils.signum(fraction); } break; case ROUND_HALF_EVEN: if (Math.abs(fraction) + parityBit > 5) { increment = Utils.signum(fraction); } break; default: throw new IllegalArgumentException("Illegal rounding mode"); } return increment; } /** * If the precision already was calculated it returns that value, otherwise * it calculates a very good approximation efficiently . Note that this * value will be <code>precision()</code> or <code>precision()-1</code> * in the worst case. * @return an approximation of <code>precision()</code> value */ private int aproxPrecision() { return ((precision > 0) ? precision : (int)((this.bitLength - 1) * LOG10_2)) + 1; } /** * It tests if a scale of type <code>long</code> fits in 32 bits. * It returns the same scale being casted to <code>int</code> type when * is possible, otherwise throws an exception. * @param longScale a 64 bit scale. * @return a 32 bit scale when is possible. * @throws <code>ArithmeticException</code> when <code>scale</code> * doesn't fit in <code>int</code> 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 approximated scale of type * <code>int</code>. if <code>longScale > Integer.MAX_VALUE</code> * the scale will be <code>Integer.MAX_VALUE</code>; if * <code>longScale < Integer.MIN_VALUE</code> the scale will be * <code>Integer.MIN_VALUE</code>; otherwise <code>longScale</code> is * casted to the type <code>int</code>. * @param longScale the scale to which the value 0 will be scaled. * @return the value 0 scaled by the closer scale of type <code>int</code>. * @see #scale */ private static BigDecimal zeroScaledBy(long longScale) { if (longScale == (int) longScale) { return valueOf(0,(int)longScale); } if (longScale >= 0) { return new BigDecimal( 0, Integer.MAX_VALUE); } return new BigDecimal( 0, Integer.MIN_VALUE); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.bitLength = intVal.bitLength(); if (this.bitLength < 64) { this.smallValue = intVal.longValue(); } } private void writeObject(ObjectOutputStream out) throws IOException { getUnscaledValue(); out.defaultWriteObject(); } private BigInteger getUnscaledValue() { if(intVal == null) { intVal = BigInteger.valueOf(smallValue); } return intVal; } private void setUnscaledValue(BigInteger unscaledValue) { this.intVal = unscaledValue; this.bitLength = unscaledValue.bitLength(); if(this.bitLength < 64) { this.smallValue = unscaledValue.longValue(); } } private static int bitLength(long smallValue) { if(smallValue < 0) { smallValue = ~smallValue; } return 64 - Utils.numberOfLeadingZeros(smallValue); } private static int bitLength(int smallValue) { if(smallValue < 0) { smallValue = ~smallValue; } return 32 - Utils.numberOfLeadingZeros(smallValue); } }