/**
         * Returns a new {@code BigDecimal} whose value is {@code this *
         * multiplicand}. The scale of the result is the sum of the scales of the
         * two arguments.
         *
         * @param multiplicand
         *            value to be multiplied with {@code this}.
         * @return {@code this * multiplicand}.
         * @throws NullPointerException
         *             if {@code multiplicand == null}.
         */

        public static BigDecimal Multiply(BigDecimal value, BigDecimal multiplicand)
        {
            long newScale = (long)value.Scale + multiplicand.Scale;

            if ((value.IsZero) || (multiplicand.IsZero))
            {
                return(BigDecimal.GetZeroScaledBy(newScale));
            }

            /* Let be: this = [u1,s1] and multiplicand = [u2,s2] so:
             * this x multiplicand = [ s1 * s2 , s1 + s2 ] */
            if (value.BitLength + multiplicand.BitLength < 64)
            {
                return(BigDecimal.Create(value.SmallValue * multiplicand.SmallValue, BigDecimal.ToIntScale(newScale)));
            }
            return(new BigDecimal(value.UnscaledValue * multiplicand.UnscaledValue, BigDecimal.ToIntScale(newScale)));
        }
示例#2
0
        /**
         * Returns a new {@code BigDecimal} whose value is {@code this} 10^{@code n}.
         * The scale of the result is {@code this.scale()} - {@code n}.
         * The precision of the result is the precision of {@code this}.
         * <p>
         * This method has the same effect as {@link #movePointRight}, except that
         * the precision is not changed.
         *
         * @param n
         *            number of places the decimal point has to be moved.
         * @return {@code this * 10^n}
         */

        public static BigDecimal ScaleByPowerOfTen(BigDecimal number, int n)
        {
            long newScale = number.Scale - (long)n;

            if (number.BitLength < 64)
            {
                //Taking care when a 0 is to be scaled
                if (number.SmallValue == 0)
                {
                    return(BigDecimal.GetZeroScaledBy(newScale));
                }

                return(BigDecimal.Create(number.SmallValue, BigDecimal.ToIntScale(newScale)));
            }

            return(new BigDecimal(number.UnscaledValue, BigDecimal.ToIntScale(newScale)));
        }
        public static BigDecimal Pow(BigDecimal number, int n)
        {
            if (n == 0)
            {
                return(BigDecimal.One);
            }
            if ((n < 0) || (n > 999999999))
            {
                // math.07=Invalid Operation
                throw new ArithmeticException(Messages.math07);                 //$NON-NLS-1$
            }
            long newScale = number.Scale * (long)n;

            // Let be: this = [u,s]   so:  this^n = [u^n, s*n]
            return((number.IsZero)
                                ? BigDecimal.GetZeroScaledBy(newScale)
                                : new BigDecimal(BigMath.Pow(number.UnscaledValue, n), BigDecimal.ToIntScale(newScale)));
        }
        public static BigDecimal MovePoint(BigDecimal number, long newScale)
        {
            if (number.IsZero)
            {
                return(BigDecimal.GetZeroScaledBy(System.Math.Max(newScale, 0)));
            }

            /* When:  'n'== Integer.MIN_VALUE  isn't possible to call to movePointRight(-n)
             * since  -Integer.MIN_VALUE == Integer.MIN_VALUE */
            if (newScale >= 0)
            {
                if (number.BitLength < 64)
                {
                    return(BigDecimal.Create(number.SmallValue, BigDecimal.ToIntScale(newScale)));
                }
                return(new BigDecimal(number.UnscaledValue, BigDecimal.ToIntScale(newScale)));
            }
            if (-newScale < BigDecimal.LongTenPow.Length &&
                number.BitLength + BigDecimal.LongTenPowBitLength[(int)-newScale] < 64)
            {
                return(BigDecimal.Create(number.SmallValue * BigDecimal.LongTenPow[(int)-newScale], 0));
            }
            return(new BigDecimal(Multiplication.MultiplyByTenPow(number.UnscaledValue, (int)-newScale), 0));
        }
        public static BigDecimal Divide(BigDecimal dividend, BigDecimal divisor)
        {
            BigInteger p = dividend.UnscaledValue;
            BigInteger q = divisor.UnscaledValue;
            BigInteger gcd;             // greatest common divisor between 'p' and 'q'
            BigInteger quotient;
            BigInteger remainder;
            long       diffScale = (long)dividend.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 = BigDecimal.FivePow.Length - 1;

            if (divisor.IsZero)
            {
                // math.04=Division by zero
                throw new ArithmeticException(Messages.math04);                 //$NON-NLS-1$
            }
            if (p.Sign == 0)
            {
                return(BigDecimal.GetZeroScaledBy(diffScale));
            }
            // To divide both by the GCD
            gcd = BigMath.Gcd(p, q);
            p   = p / gcd;
            q   = q / gcd;
            // To simplify all "2" factors of q, dividing by 2^k
            k = q.LowestSetBit;
            q = q >> k;
            // To simplify all "5" factors of q, dividing by 5^l
            do
            {
                quotient = BigMath.DivideAndRemainder(q, BigDecimal.FivePow[i], out remainder);
                if (remainder.Sign == 0)
                {
                    l += i;
                    if (i < lastPow)
                    {
                        i++;
                    }
                    q = quotient;
                }
                else
                {
                    if (i == 1)
                    {
                        break;
                    }
                    i = 1;
                }
            } while (true);
            // If  abs(q) != 1  then the quotient is periodic
            if (!BigMath.Abs(q).Equals(BigInteger.One))
            {
                // math.05=Non-terminating decimal expansion; no exact representable decimal result.
                throw new ArithmeticException(Messages.math05);                 //$NON-NLS-1$
            }
            // The sign of the is fixed and the quotient will be saved in 'p'
            if (q.Sign < 0)
            {
                p = -p;
            }
            // Checking if the new scale is out of range
            newScale = BigDecimal.ToIntScale(diffScale + System.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 << -i;
            return(new BigDecimal(p, newScale));
        }
        public static BigDecimal DivideToIntegralValue(BigDecimal dividend, BigDecimal divisor, MathContext mc)
        {
            int        mcPrecision   = mc.Precision;
            int        diffPrecision = dividend.Precision - divisor.Precision;
            int        lastPow       = BigDecimal.TenPow.Length - 1;
            long       diffScale     = (long)dividend.Scale - divisor.Scale;
            long       newScale      = diffScale;
            long       quotPrecision = diffPrecision - diffScale + 1;
            BigInteger quotient;
            BigInteger remainder;

            // In special cases it call the dual method
            if ((mcPrecision == 0) || (dividend.IsZero) || (divisor.IsZero))
            {
                return(DivideToIntegralValue(dividend, divisor));
            }
            // Let be:   this = [u1,s1]   and   divisor = [u2,s2]
            if (quotPrecision <= 0)
            {
                quotient = BigInteger.Zero;
            }
            else if (diffScale == 0)
            {
                // CASE s1 == s2:  to calculate   u1 / u2
                quotient = dividend.UnscaledValue / divisor.UnscaledValue;
            }
            else if (diffScale > 0)
            {
                // CASE s1 >= s2:  to calculate   u1 / (u2 * 10^(s1-s2)
                quotient = dividend.UnscaledValue / (divisor.UnscaledValue * Multiplication.PowerOf10(diffScale));
                // To chose  10^newScale  to get a quotient with at least 'mc.precision()' digits
                newScale = System.Math.Min(diffScale, System.Math.Max(mcPrecision - quotPrecision + 1, 0));
                // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale
                quotient = quotient * 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 = System.Math.Min(-diffScale, System.Math.Max((long)mcPrecision - diffPrecision, 0));
                long compRemDiv;
                // Let be:   (u1 * 10^exp) / u2 = [q,r]
                quotient = BigMath.DivideAndRemainder(dividend.UnscaledValue * Multiplication.PowerOf10(exp),
                                                      divisor.UnscaledValue, out remainder);
                newScale += exp;                 // To fix the scale
                exp       = -newScale;           // The remaining power of ten
                // If after division there is a remainder...
                if ((remainder.Sign != 0) && (exp > 0))
                {
                    // Log10(r) + ((s2 - s1) - exp) > mc.precision ?
                    compRemDiv = (new BigDecimal(remainder)).Precision
                                 + exp - divisor.Precision;
                    if (compRemDiv == 0)
                    {
                        // To calculate:  (r * 10^exp2) / u2
                        remainder  = (remainder * Multiplication.PowerOf10(exp)) / divisor.UnscaledValue;
                        compRemDiv = System.Math.Abs(remainder.Sign);
                    }
                    if (compRemDiv > 0)
                    {
                        // The quotient won't fit in 'mc.precision()' digits
                        // math.06=Division impossible
                        throw new ArithmeticException(Messages.math06);                         //$NON-NLS-1$
                    }
                }
            }
            // Fast return if the quotient is zero
            if (quotient.Sign == 0)
            {
                return(BigDecimal.GetZeroScaledBy(diffScale));
            }
            BigInteger strippedBI      = quotient;
            BigDecimal integralValue   = new BigDecimal(quotient);
            long       resultPrecision = integralValue.Precision;
            int        i = 1;

            // To strip trailing zeros until the specified precision is reached
            while (!BigInteger.TestBit(strippedBI, 0))
            {
                quotient = BigMath.DivideAndRemainder(strippedBI, BigDecimal.TenPow[i], out remainder);
                if ((remainder.Sign == 0) &&
                    ((resultPrecision - i >= mcPrecision) ||
                     (newScale - i >= diffScale)))
                {
                    resultPrecision -= i;
                    newScale        -= i;
                    if (i < lastPow)
                    {
                        i++;
                    }
                    strippedBI = quotient;
                }
                else
                {
                    if (i == 1)
                    {
                        break;
                    }
                    i = 1;
                }
            }
            // To check if the result fit in 'mc.precision()' digits
            if (resultPrecision > mcPrecision)
            {
                // math.06=Division impossible
                throw new ArithmeticException(Messages.math06);                 //$NON-NLS-1$
            }
            integralValue.Scale = BigDecimal.ToIntScale(newScale);
            integralValue.SetUnscaledValue(strippedBI);
            return(integralValue);
        }
        public static BigDecimal DivideToIntegralValue(BigDecimal dividend, BigDecimal divisor)
        {
            BigInteger integralValue;          // the integer of result
            BigInteger powerOfTen;             // some power of ten
            BigInteger quotient;
            BigInteger remainder;
            long       newScale  = (long)dividend.Scale - divisor.Scale;
            long       tempScale = 0;
            int        i         = 1;
            int        lastPow   = BigDecimal.TenPow.Length - 1;

            if (divisor.IsZero)
            {
                // math.04=Division by zero
                throw new ArithmeticException(Messages.math04);                 //$NON-NLS-1$
            }
            if ((divisor.AproxPrecision() + newScale > dividend.AproxPrecision() + 1L) ||
                (dividend.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 = dividend.UnscaledValue / divisor.UnscaledValue;
            }
            else if (newScale > 0)
            {
                powerOfTen    = Multiplication.PowerOf10(newScale);
                integralValue = dividend.UnscaledValue / (divisor.UnscaledValue * powerOfTen);
                integralValue = integralValue * powerOfTen;
            }
            else
            {
                // (newScale < 0)
                powerOfTen    = Multiplication.PowerOf10(-newScale);
                integralValue = (dividend.UnscaledValue * powerOfTen) / divisor.UnscaledValue;
                // To strip trailing zeros approximating to the preferred scale
                while (!BigInteger.TestBit(integralValue, 0))
                {
                    quotient = BigMath.DivideAndRemainder(integralValue, BigDecimal.TenPow[i], out remainder);
                    if ((remainder.Sign == 0) &&
                        (tempScale - i >= newScale))
                    {
                        tempScale -= i;
                        if (i < lastPow)
                        {
                            i++;
                        }
                        integralValue = quotient;
                    }
                    else
                    {
                        if (i == 1)
                        {
                            break;
                        }
                        i = 1;
                    }
                }
                newScale = tempScale;
            }
            return((integralValue.Sign == 0)
                                ? BigDecimal.GetZeroScaledBy(newScale)
                                : new BigDecimal(integralValue, BigDecimal.ToIntScale(newScale)));
        }