Пример #1
0
        public BigDecimal multiply(BigDecimal multiplicand)
        {
            long newScale = (long)this._scale + multiplicand._scale;

            if ((this.isZero()) || (multiplicand.isZero())) {
                return zeroScaledBy(newScale);
            }
            /* Let be: this = [u1,s1] and multiplicand = [u2,s2] so:
             * this x multiplicand = [ s1 * s2 , s1 + s2 ] */
            if(this._bitLength + multiplicand._bitLength < 64) {
                return valueOf(this.smallValue*multiplicand.smallValue,toIntScale(newScale));
            }
            return new BigDecimal(this.getUnscaledValue().multiply(
                                      multiplicand.getUnscaledValue()), toIntScale(newScale));
        }
Пример #2
0
        public BigDecimal divideToIntegralValue(BigDecimal divisor)
        {
            BigInteger integralValue; // the integer of result
            BigInteger powerOfTen; // some power of ten
            BigInteger[] quotAndRem = {getUnscaledValue()};
            long newScale = (long)this._scale - divisor._scale;
            long tempScale = 0;
            int i = 1;
            int lastPow = TEN_POW.Length - 1;

            if (divisor.isZero()) {
                throw new ArithmeticException("Division by zero");
            }
            if ((divisor.aproxPrecision() + newScale > this.aproxPrecision() + 1L)
                || (this.isZero())) {
                /* If the divisor's integer part is greater than this's integer part,
                 * the result must be zero with the appropriate scale */
                integralValue = BigInteger.ZERO;
            } else if (newScale == 0) {
                integralValue = getUnscaledValue().divide( divisor.getUnscaledValue() );
            } else if (newScale > 0) {
                powerOfTen = Multiplication.powerOf10(newScale);
                integralValue = getUnscaledValue().divide( divisor.getUnscaledValue().multiply(powerOfTen) );
                integralValue = integralValue.multiply(powerOfTen);
            } else {// (newScale < 0)
                powerOfTen = Multiplication.powerOf10(-newScale);
                integralValue = getUnscaledValue().multiply(powerOfTen).divide( divisor.getUnscaledValue() );
                // To strip trailing zeros approximating to the preferred scale
                while (!integralValue.testBit(0)) {
                    quotAndRem = integralValue.divideAndRemainder(TEN_POW[i]);
                    if ((quotAndRem[1].signum() == 0)
                        && (tempScale - i >= newScale)) {
                        tempScale -= i;
                        if (i < lastPow) {
                            i++;
                        }
                        integralValue = quotAndRem[0];
                    } else {
                        if (i == 1) {
                            break;
                        }
                        i = 1;
                    }
                }
                newScale = tempScale;
            }
            return ((integralValue.signum() == 0)
                    ? zeroScaledBy(newScale)
                    : new BigDecimal(integralValue, toIntScale(newScale)));
        }
Пример #3
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;
 }
Пример #4
0
        public BigDecimal divide(BigDecimal divisor)
        {
            BigInteger p = this.getUnscaledValue();
            BigInteger q = divisor.getUnscaledValue();
            BigInteger gcd; // greatest common divisor between 'p' and 'q'
            BigInteger[] quotAndRem;
            long diffScale = (long)_scale - divisor._scale;
            int newScale; // the new scale for final quotient
            int k; // number of factors "2" in 'q'
            int l = 0; // number of factors "5" in 'q'
            int i = 1;
            int lastPow = FIVE_POW.Length - 1;

            if (divisor.isZero()) {
                throw new ArithmeticException("Division by zero");
            }
            if (p.signum() == 0) {
                return zeroScaledBy(diffScale);
            }
            // To divide both by the GCD
            gcd = p.gcd(q);
            p = p.divide(gcd);
            q = q.divide(gcd);
            // To simplify all "2" factors of q, dividing by 2^k
            k = q.getLowestSetBit();
            q = q.shiftRight(k);
            // To simplify all "5" factors of q, dividing by 5^l
            do {
                quotAndRem = q.divideAndRemainder(FIVE_POW[i]);
                if (quotAndRem[1].signum() == 0) {
                    l += i;
                    if (i < lastPow) {
                        i++;
                    }
                    q = quotAndRem[0];
                } else {
                    if (i == 1) {
                        break;
                    }
                    i = 1;
                }
            } while (true);
            // If  abs(q) != 1  then the quotient is periodic
            if (!q.abs().Equals(BigInteger.ONE)) {
                throw new ArithmeticException("Non-terminating decimal expansion; no exact representable decimal result.");
            }
            // The sign of the is fixed and the quotient will be saved in 'p'
            if (q.signum() < 0) {
                p = p.negate();
            }
            // Checking if the new scale is out of range
            newScale = toIntScale(diffScale + Math.Max(k, l));
            // k >= 0  and  l >= 0  implies that  k - l  is in the 32-bit range
            i = k - l;

            p = (i > 0) ? Multiplication.multiplyByFivePow(p, i)
                : p.shiftLeft(-i);
            return new BigDecimal(p, newScale);
        }
Пример #5
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);
 }
Пример #6
0
        public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
        {
            // Let be: this = [u1,s1]  and  divisor = [u2,s2]
            if (divisor.isZero()) {
                throw new ArithmeticException("Division by zero");
            }

            long diffScale = ((long)this._scale - divisor._scale) - scale;
            if(this._bitLength < 64 && divisor._bitLength < 64 ) {
                if(diffScale == 0) {
                    return dividePrimitiveLongs(this.smallValue,
                                                divisor.smallValue,
                                                scale,
                                                roundingMode );
                } else if(diffScale > 0) {
                    if(diffScale < LONG_TEN_POW.Length &&
                       divisor._bitLength + LONG_TEN_POW_BIT_LENGTH[(int)diffScale] < 64) {
                        return dividePrimitiveLongs(this.smallValue,
                                                    divisor.smallValue*LONG_TEN_POW[(int)diffScale],
                                                    _scale,
                                                    roundingMode);
                    }
                } else { // diffScale < 0
                    if(-diffScale < LONG_TEN_POW.Length &&
                       this._bitLength + LONG_TEN_POW_BIT_LENGTH[(int)-diffScale] < 64) {
                        return dividePrimitiveLongs(this.smallValue*LONG_TEN_POW[(int)-diffScale],
                                                    divisor.smallValue,
                                                    scale,
                                                    roundingMode);
                    }

                }
            }
            BigInteger scaledDividend = this.getUnscaledValue();
            BigInteger scaledDivisor = divisor.getUnscaledValue(); // for scaling of 'u2'

            if (diffScale > 0) {
                // Multiply 'u2'  by:  10^((s1 - s2) - scale)
                scaledDivisor = Multiplication.multiplyByTenPow(scaledDivisor, (int)diffScale);
            } else if (diffScale < 0) {
                // Multiply 'u1'  by:  10^(scale - (s1 - s2))
                scaledDividend  = Multiplication.multiplyByTenPow(scaledDividend, (int)-diffScale);
            }
            return divideBigIntegers(scaledDividend, scaledDivisor, scale, roundingMode);
        }
Пример #7
0
        public int compareTo(BigDecimal val)
        {
            int thisSign = signum();
            int valueSign = val.signum();

            if( thisSign == valueSign) {
                if(this._scale == val._scale && this._bitLength<64 && val._bitLength<64 ) {
                    return (smallValue < val.smallValue) ? -1 : (smallValue > val.smallValue) ? 1 : 0;
                }
                long diffScale = (long)this._scale - val._scale;
                int diffPrecision = this.aproxPrecision() - val.aproxPrecision();
                if (diffPrecision > diffScale + 1) {
                    return thisSign;
                } else if (diffPrecision < diffScale - 1) {
                    return -thisSign;
                } else {// thisSign == val.signum()  and  diffPrecision is aprox. diffScale
                    BigInteger thisUnscaled = this.getUnscaledValue();
                    BigInteger valUnscaled = val.getUnscaledValue();
                    // If any of both precision is bigger, append zeros to the shorter one
                    if (diffScale < 0) {
                        thisUnscaled = thisUnscaled.multiply(Multiplication.powerOf10(-diffScale));
                    } else if (diffScale > 0) {
                        valUnscaled = valUnscaled.multiply(Multiplication.powerOf10(diffScale));
                    }
                    return thisUnscaled.compareTo(valUnscaled);
                }
            } else if (thisSign < valueSign) {
                return -1;
            } else  {
                return 1;
            }
        }
Пример #8
0
 public BigDecimal add(BigDecimal augend)
 {
     int diffScale = this._scale - augend._scale;
     // Fast return when some operand is zero
     if (this.isZero()) {
         if (diffScale <= 0) {
             return augend;
         }
         if (augend.isZero()) {
             return this;
         }
     } else if (augend.isZero()) {
         if (diffScale >= 0) {
             return this;
         }
     }
     // Let be:  this = [u1,s1]  and  augend = [u2,s2]
     if (diffScale == 0) {
         // case s1 == s2: [u1 + u2 , s1]
         if (Math.Max(this._bitLength, augend._bitLength) + 1 < 64) {
             return valueOf(this.smallValue + augend.smallValue, this._scale);
         }
         return new BigDecimal(this.getUnscaledValue().add(augend.getUnscaledValue()), this._scale);
     } else if (diffScale > 0) {
         // case s1 > s2 : [(u1 + u2) * 10 ^ (s1 - s2) , s1]
         return addAndMult10(this, augend, diffScale);
     } else {// case s2 > s1 : [(u2 + u1) * 10 ^ (s2 - s1) , s2]
         return addAndMult10(augend, this, -diffScale);
     }
 }
Пример #9
0
 private static BigDecimal addAndMult10(BigDecimal thisValue,BigDecimal augend, int diffScale)
 {
     if(diffScale < LONG_TEN_POW.Length &&
        Math.Max(thisValue._bitLength,augend._bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) {
         return valueOf(thisValue.smallValue+augend.smallValue*LONG_TEN_POW[diffScale],thisValue._scale);
     }
     return new BigDecimal(thisValue.getUnscaledValue().add(
                               Multiplication.multiplyByTenPow(augend.getUnscaledValue(),diffScale)), thisValue._scale);
 }
Пример #10
0
 public BigDecimal subtract(BigDecimal subtrahend)
 {
     int diffScale = this._scale - subtrahend._scale;
     // Fast return when some operand is zero
     if (this.isZero()) {
         if (diffScale <= 0) {
             return subtrahend.negate();
         }
         if (subtrahend.isZero()) {
             return this;
         }
     } else if (subtrahend.isZero()) {
         if (diffScale >= 0) {
             return this;
         }
     }
     // Let be: this = [u1,s1] and subtrahend = [u2,s2] so:
     if (diffScale == 0) {
         // case s1 = s2 : [u1 - u2 , s1]
         if (Math.Max(this._bitLength, subtrahend._bitLength) + 1 < 64) {
             return valueOf(this.smallValue - subtrahend.smallValue,this._scale);
         }
         return new BigDecimal(this.getUnscaledValue().subtract(subtrahend.getUnscaledValue()), this._scale);
     } else if (diffScale > 0) {
         // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ]
         if(diffScale < LONG_TEN_POW.Length &&
            Math.Max(this._bitLength,subtrahend._bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) {
             return valueOf(this.smallValue-subtrahend.smallValue*LONG_TEN_POW[diffScale],this._scale);
         }
         return new BigDecimal(this.getUnscaledValue().subtract(
                                   Multiplication.multiplyByTenPow(subtrahend.getUnscaledValue(),diffScale)), this._scale);
     } else {// case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ]
         diffScale = -diffScale;
         if(diffScale < LONG_TEN_POW.Length &&
            Math.Max(this._bitLength+LONG_TEN_POW_BIT_LENGTH[diffScale],subtrahend._bitLength)+1<64) {
             return valueOf(this.smallValue*LONG_TEN_POW[diffScale]-subtrahend.smallValue,subtrahend._scale);
         }
         return new BigDecimal(Multiplication.multiplyByTenPow(this.getUnscaledValue(),diffScale)
                               .subtract(subtrahend.getUnscaledValue()), subtrahend._scale);
     }
 }