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