Ejemplo 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;
 }
Ejemplo n.º 2
0
        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;
        }
Ejemplo n.º 3
0
 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);
 }
Ejemplo n.º 4
0
 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);
 }
Ejemplo n.º 5
0
 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;
 }
Ejemplo n.º 6
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]);
 }
Ejemplo n.º 7
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);
 }