Пример #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;
 }