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 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) || ((isZero()) && (n > 0))) { return pow(n); } if ((m > 999999999) || ((mcPrecision == 0) && (n < 0)) || ((mcPrecision > 0) && (elength > mcPrecision))) { // math.07=Invalid Operation 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 = 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; }
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 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.isZero()) || (this.isZero()) || (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 = Multiplication.multiplyByPositiveInt(larger.getUnscaledValue(),10) .add(BigInteger.valueOf(largerSignum)); } else { tempBI = larger.getUnscaledValue().subtract( BigInteger.valueOf(largerSignum)); tempBI = Multiplication.multiplyByPositiveInt(tempBI,10) .add(BigInteger.valueOf(largerSignum * 9)); } // Rounding the improved adding larger = new BigDecimal(tempBI, larger._scale + 1); return larger.round(mc); }
private void smallRound(MathContext mc, int discardedPrecision) { long sizeOfFraction = LONG_TEN_POW[discardedPrecision]; long newScale = (long)_scale - discardedPrecision; long unscaledVal = smallValue; // Getting the integer 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 = longCompareTo(Math.Abs(fraction) << 1,sizeOfFraction); // To look if there is a carry integer += roundingBehavior( ((int)integer) & 1, Math.Sign(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 internal fields _scale = toIntScale(newScale); _precision = mc.getPrecision(); smallValue = integer; _bitLength = bitLength(integer); intVal = null; }
private void inplaceRound(MathContext mc) { int mcPrecision = mc.getPrecision(); if (aproxPrecision() - mcPrecision <= 0 || mcPrecision == 0) { return; } int discardedPrecision = precision() - mcPrecision; // If no rounding is necessary it returns immediately if ((discardedPrecision <= 0)) { return; } // When the number is small perform an efficient rounding if (this._bitLength < 64) { smallRound(mc, discardedPrecision); return; } // Getting the integer part and the discarded fraction BigInteger sizeOfFraction = Multiplication.powerOf10(discardedPrecision); BigInteger[] integerAndFraction = getUnscaledValue().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().shiftLeftOneBit().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 internal fields _scale = toIntScale(newScale); _precision = mcPrecision; setUnscaledValue(integerAndFraction[0]); }
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.isZero()) || (this.isZero()) || (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 = Multiplication.multiplyByPositiveInt(this.getUnscaledValue(), 10) .add(BigInteger.valueOf(thisSignum)); } else { tempBI = this.getUnscaledValue().subtract(BigInteger.valueOf(thisSignum)); tempBI = Multiplication.multiplyByPositiveInt(tempBI, 10) .add(BigInteger.valueOf(thisSignum * 9)); } // Rounding the improved subtracting leftOperand = new BigDecimal(tempBI, this._scale + 1); return leftOperand.round(mc); } } // No optimization is done return subtract(subtrahend).round(mc); }