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; }
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]); }