Esempio n. 1
0
 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;
 }
Esempio n. 2
0
 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]);
 }