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 divideToIntegralValue(BigDecimal divisor) { BigInteger integralValue; // the integer of result BigInteger powerOfTen; // some power of ten BigInteger[] quotAndRem = {getUnscaledValue()}; long newScale = (long)this._scale - divisor._scale; long tempScale = 0; int i = 1; int lastPow = TEN_POW.Length - 1; if (divisor.isZero()) { throw new ArithmeticException("Division by zero"); } if ((divisor.aproxPrecision() + newScale > this.aproxPrecision() + 1L) || (this.isZero())) { /* If the divisor's integer part is greater than this's integer part, * the result must be zero with the appropriate scale */ integralValue = BigInteger.ZERO; } else if (newScale == 0) { integralValue = getUnscaledValue().divide( divisor.getUnscaledValue() ); } else if (newScale > 0) { powerOfTen = Multiplication.powerOf10(newScale); integralValue = getUnscaledValue().divide( divisor.getUnscaledValue().multiply(powerOfTen) ); integralValue = integralValue.multiply(powerOfTen); } else {// (newScale < 0) powerOfTen = Multiplication.powerOf10(-newScale); integralValue = getUnscaledValue().multiply(powerOfTen).divide( divisor.getUnscaledValue() ); // To strip trailing zeros approximating 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))); }
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.isZero()) || (divisor.isZero())) { 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.getUnscaledValue().divide( divisor.getUnscaledValue() ); } else if (diffScale > 0) { // CASE s1 >= s2: to calculate u1 / (u2 * 10^(s1-s2) quotAndRem[0] = this.getUnscaledValue().divide( divisor.getUnscaledValue().multiply(Multiplication.powerOf10(diffScale)) ); // To chose 10^newScale to get a quotient with at least 'mc.precision()' digits newScale = Math.Min(diffScale, Math.Max(mcPrecision - quotPrecision + 1, 0)); // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale quotAndRem[0] = quotAndRem[0].multiply(Multiplication.powerOf10(newScale)); } else {// CASE s2 > s1: /* To calculate the minimum 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.getUnscaledValue().multiply(Multiplication.powerOf10(exp)). divideAndRemainder(divisor.getUnscaledValue()); 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 - divisor.precision(); if (compRemDiv == 0) { // To calculate: (r * 10^exp2) / u2 quotAndRem[1] = quotAndRem[1].multiply(Multiplication.powerOf10(exp)). divide(divisor.getUnscaledValue()); 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"); } integralValue._scale = toIntScale(newScale); integralValue.setUnscaledValue(strippedBI); return integralValue; }
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; 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 > 0) ? Multiplication.multiplyByFivePow(p, i) : p.shiftLeft(-i); return new BigDecimal(p, newScale); }
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 = mc.getPrecision() + 2L + divisor.aproxPrecision() - 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 = {getUnscaledValue()}; // In special cases it reduces the problem to call the dual method if ((mc.getPrecision() == 0) || (this.isZero()) || (divisor.isZero())) { return this.divide(divisor); } if (traillingZeros > 0) { // To append trailing zeros at end of dividend quotAndRem[0] = getUnscaledValue().multiply( Multiplication.powerOf10(traillingZeros) ); newScale += traillingZeros; } quotAndRem = quotAndRem[0].divideAndRemainder( divisor.getUnscaledValue() ); 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].shiftLeftOneBit().compareTo( divisor.getUnscaledValue() ); // 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); }
public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) { // Let be: this = [u1,s1] and divisor = [u2,s2] if (divisor.isZero()) { throw new ArithmeticException("Division by zero"); } 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); }
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 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); } }