コード例 #1
0
        /**
         * Returns this {@code BigDecimal} as a big integer instance if it has no
         * fractional part. If this {@code BigDecimal} has a fractional part, i.e.
         * if rounding would be necessary, an {@code ArithmeticException} is thrown.
         *
         * @return this {@code BigDecimal} as a big integer value.
         * @throws ArithmeticException
         *             if rounding is necessary.
         */

        public BigInteger ToBigIntegerExact()
        {
            if ((_scale == 0) || (IsZero))
            {
                return(GetUnscaledValue());
            }
            else if (_scale < 0)
            {
                return(GetUnscaledValue() * Multiplication.PowerOf10(-(long)_scale));
            }
            else
            {
                // (scale > 0)
                BigInteger integer;
                BigInteger fraction;

                // An optimization before do a heavy division
                if ((_scale > AproxPrecision()) || (_scale > GetUnscaledValue().LowestSetBit))
                {
                    // math.08=Rounding necessary
                    throw new ArithmeticException(Messages.math08);                     //$NON-NLS-1$
                }

                integer = BigMath.DivideAndRemainder(GetUnscaledValue(), Multiplication.PowerOf10(_scale), out fraction);
                if (fraction.Sign != 0)
                {
                    // It exists a non-zero fractional part
                    // math.08=Rounding necessary
                    throw new ArithmeticException(Messages.math08);                     //$NON-NLS-1$
                }

                return(integer);
            }
        }
コード例 #2
0
        private void TestDiv(BigInteger i1, BigInteger i2)
        {
            BigInteger q = i1 / i2;
            BigInteger r = BigMath.Remainder(i1, i2);
            BigInteger remainder;
            BigInteger quotient = BigMath.DivideAndRemainder(i1, i2, out remainder);

            Assert.True(q.Equals(quotient), "Divide and DivideAndRemainder do not agree");
            Assert.True(r.Equals(remainder), "Remainder and DivideAndRemainder do not agree");
            Assert.True(q.Sign != 0 || q.Equals(zero), "signum and equals(zero) do not agree on quotient");
            Assert.True(r.Sign != 0 || r.Equals(zero), "signum and equals(zero) do not agree on remainder");
            Assert.True(q.Sign == 0 || q.Sign == i1.Sign * i2.Sign, "wrong sign on quotient");
            Assert.True(r.Sign == 0 || r.Sign == i1.Sign, "wrong sign on remainder");
            Assert.True(BigMath.Abs(r).CompareTo(BigMath.Abs(i2)) < 0, "remainder out of range");
            Assert.True(((BigMath.Abs(q) + one) * BigMath.Abs(i2)).CompareTo(BigMath.Abs(i1)) > 0, "quotient too small");
            Assert.True((BigMath.Abs(q) * BigMath.Abs(i2)).CompareTo(BigMath.Abs(i1)) <= 0, "quotient too large");
            BigInteger p = q * i2;
            BigInteger a = p + r;

            Assert.True(a.Equals(i1), "(a/b)*b+(a%b) != a");
            try {
                BigInteger mod = i1 % i2;
                Assert.True(mod.Sign >= 0, "mod is negative");
                Assert.True(BigMath.Abs(mod).CompareTo(BigMath.Abs(i2)) < 0, "mod out of range");
                Assert.True(r.Sign < 0 || r.Equals(mod), "positive remainder == mod");
                Assert.True(r.Sign >= 0 || r.Equals(mod - i2), "negative remainder == mod - divisor");
            } catch (ArithmeticException e) {
                Assert.True(i2.Sign <= 0, "mod fails on negative divisor only");
            }
        }
コード例 #3
0
        public void DivideAndRemainderBigInteger()
        {
            BigInteger remainder;

            Assert.Throws <ArithmeticException>(() => BigMath.DivideAndRemainder(largePos, zero, out remainder));
            Assert.Throws <ArithmeticException>(() => BigMath.DivideAndRemainder(bi1, zero, out remainder));
            Assert.Throws <ArithmeticException>(() => BigMath.DivideAndRemainder(-bi3, zero, out remainder));
            Assert.Throws <ArithmeticException>(() => BigMath.DivideAndRemainder(zero, zero, out remainder));
        }
コード例 #4
0
        public static BigDecimal DivideBigIntegers(BigInteger scaledDividend, BigInteger scaledDivisor, int scale,
                                                   RoundingMode roundingMode)
        {
            BigInteger remainder;
            BigInteger quotient = BigMath.DivideAndRemainder(scaledDividend, scaledDivisor, out remainder);

            if (remainder.Sign == 0)
            {
                return(new BigDecimal(quotient, scale));
            }
            int sign = scaledDividend.Sign * scaledDivisor.Sign;
            int compRem;             // 'compare to remainder'

            if (scaledDivisor.BitLength < 63)
            {
                // 63 in order to avoid out of long after <<1
                long rem     = remainder.ToInt64();
                long divisor = scaledDivisor.ToInt64();
                compRem = BigDecimal.LongCompareTo(System.Math.Abs(rem) << 1, System.Math.Abs(divisor));
                // To look if there is a carry
                compRem = BigDecimal.RoundingBehavior(BigInteger.TestBit(quotient, 0) ? 1 : 0,
                                                      sign * (5 + compRem), roundingMode);
            }
            else
            {
                // Checking if:  remainder * 2 >= scaledDivisor
                compRem = BigMath.Abs(remainder).ShiftLeftOneBit().CompareTo(BigMath.Abs(scaledDivisor));
                compRem = BigDecimal.RoundingBehavior(BigInteger.TestBit(quotient, 0) ? 1 : 0,
                                                      sign * (5 + compRem), roundingMode);
            }
            if (compRem != 0)
            {
                if (quotient.BitLength < 63)
                {
                    return(BigDecimal.Create(quotient.ToInt64() + compRem, scale));
                }
                quotient += BigInteger.FromInt64(compRem);
                return(new BigDecimal(quotient, scale));
            }
            // Constructing the result with the appropriate unscaled value
            return(new BigDecimal(quotient, scale));
        }
コード例 #5
0
        /**
         * Returns this {@code BigDecimal} as a double value. If {@code this} is too
         * big to be represented as an float, then {@code Double.POSITIVE_INFINITY}
         * or {@code Double.NEGATIVE_INFINITY} is returned.
         * <p>
         * Note, that if the unscaled value has more than 53 significant digits,
         * then this decimal cannot be represented exactly in a double variable. In
         * this case the result is rounded.
         * <p>
         * For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be
         * represented exactly as a double, and thus {@code x1.equals(new
         * BigDecimal(x1.ToDouble())} returns {@code false} for this case.
         * <p>
         * Similarly, if the instance {@code new BigDecimal(9007199254740993L)} is
         * converted to a double, the result is {@code 9.007199254740992E15}.
         * <p>
         *
         * @return this {@code BigDecimal} as a double value.
         */

        public double ToDouble()
        {
            int        sign     = Sign;
            int        exponent = 1076;      // bias + 53
            int        lowestSetBit;
            int        discardedSize;
            long       powerOfTwo = this._bitLength - (long)(_scale / Log10Of2);
            long       bits;       // IEEE-754 Standard
            long       tempBits;   // for temporal calculations
            BigInteger mantisa;

            if ((powerOfTwo < -1074) || (sign == 0))
            {
                // Cases which 'this' is very small
                return(sign * 0.0d);
            }
            else if (powerOfTwo > 1025)
            {
                // Cases which 'this' is very large
                return(sign * Double.PositiveInfinity);
            }

            mantisa = BigMath.Abs(GetUnscaledValue());

            // Let be:  this = [u,s], with s > 0
            if (_scale <= 0)
            {
                // mantisa = abs(u) * 10^s
                mantisa = mantisa * Multiplication.PowerOf10(-_scale);
            }
            else
            {
                // (scale > 0)
                BigInteger quotient;
                BigInteger remainder;
                BigInteger powerOfTen = Multiplication.PowerOf10(_scale);
                int        k          = 100 - (int)powerOfTwo;
                int        compRem;

                if (k > 0)
                {
                    /* Computing (mantisa * 2^k) , where 'k' is a enough big
                     * power of '2' to can divide by 10^s */
                    mantisa   = mantisa << k;
                    exponent -= k;
                }

                // Computing (mantisa * 2^k) / 10^s
                quotient = BigMath.DivideAndRemainder(mantisa, powerOfTen, out remainder);

                // To check if the fractional part >= 0.5
                compRem = remainder.ShiftLeftOneBit().CompareTo(powerOfTen);

                // To add two rounded bits at end of mantisa
                mantisa   = (quotient << 2) + BigInteger.FromInt64((compRem * (compRem + 3)) / 2 + 1);
                exponent -= 2;
            }
            lowestSetBit  = mantisa.LowestSetBit;
            discardedSize = mantisa.BitLength - 54;
            if (discardedSize > 0)
            {
                // (n > 54)
                // mantisa = (abs(u) * 10^s) >> (n - 54)
                bits     = (mantisa >> discardedSize).ToInt64();
                tempBits = bits;

                // #bits = 54, to check if the discarded fraction produces a carry
                if ((((bits & 1) == 1) && (lowestSetBit < discardedSize)) ||
                    ((bits & 3) == 3))
                {
                    bits += 2;
                }
            }
            else
            {
                // (n <= 54)
                // mantisa = (abs(u) * 10^s) << (54 - n)
                bits     = mantisa.ToInt64() << -discardedSize;
                tempBits = bits;

                // #bits = 54, to check if the discarded fraction produces a carry:
                if ((bits & 3) == 3)
                {
                    bits += 2;
                }
            }

            // Testing bit 54 to check if the carry creates a new binary digit
            if ((bits & 0x40000000000000L) == 0)
            {
                // To drop the last bit of mantisa (first discarded)
                bits >>= 1;

                // exponent = 2^(s-n+53+bias)
                exponent += discardedSize;
            }
            else
            {
                // #bits = 54
                bits    >>= 2;
                exponent += discardedSize + 1;
            }

            // To test if the 53-bits number fits in 'double'
            if (exponent > 2046)
            {
                // (exponent - bias > 1023)
                return(sign * Double.PositiveInfinity);
            }

            if (exponent <= 0)
            {
                // (exponent - bias <= -1023)
                // Denormalized numbers (having exponent == 0)
                if (exponent < -53)
                {
                    // exponent - bias < -1076
                    return(sign * 0.0d);
                }

                // -1076 <= exponent - bias <= -1023
                // To discard '- exponent + 1' bits
                bits     = tempBits >> 1;
                tempBits = bits & Utils.URShift(-1L, (63 + exponent));
                bits   >>= (-exponent);

                // To test if after discard bits, a new carry is generated
                if (((bits & 3) == 3) || (((bits & 1) == 1) && (tempBits != 0) &&
                                          (lowestSetBit < discardedSize)))
                {
                    bits += 1;
                }
                exponent = 0;
                bits   >>= 1;
            }

            // Construct the 64 double bits: [sign(1), exponent(11), mantisa(52)]
            // bits = (long)((ulong)sign & 0x8000000000000000L) | ((long)exponent << 52) | (bits & 0xFFFFFFFFFFFFFL);
            bits = sign & Int64.MinValue | ((long)exponent << 52) | (bits & 0xFFFFFFFFFFFFFL);
            return(BitConverter.Int64BitsToDouble(bits));
        }
コード例 #6
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));
        }
コード例 #7
0
        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);
        }
コード例 #8
0
        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)));
        }
コード例 #9
0
        public static BigDecimal Divide(BigDecimal dividend, 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.Precision + 2L
                                  + divisor.AproxPrecision() - dividend.AproxPrecision();
            long       diffScale = (long)dividend.Scale - divisor.Scale;
            long       newScale  = diffScale;                  // scale of the final quotient
            int        compRem;                                // to compare the remainder
            int        i       = 1;                            // index
            int        lastPow = BigDecimal.TenPow.Length - 1; // last power of ten
            BigInteger integerQuot;                            // for temporal results
            BigInteger quotient = dividend.UnscaledValue;
            BigInteger remainder;

            // In special cases it reduces the problem to call the dual method
            if ((mc.Precision == 0) || (dividend.IsZero) || (divisor.IsZero))
            {
                return(Divide(dividend, divisor));
            }

            if (traillingZeros > 0)
            {
                // To append trailing zeros at end of dividend
                quotient  = dividend.UnscaledValue * Multiplication.PowerOf10(traillingZeros);
                newScale += traillingZeros;
            }
            quotient    = BigMath.DivideAndRemainder(quotient, divisor.UnscaledValue, out remainder);
            integerQuot = quotient;
            // Calculating the exact quotient with at least 'mc.precision()' digits
            if (remainder.Sign != 0)
            {
                // Checking if:   2 * remainder >= divisor ?
                compRem = remainder.ShiftLeftOneBit().CompareTo(divisor.UnscaledValue);
                // quot := quot * 10 + r;     with 'r' in {-6,-5,-4, 0,+4,+5,+6}
                integerQuot = (integerQuot * BigInteger.Ten) +
                              BigInteger.FromInt64(quotient.Sign * (5 + compRem));
                newScale++;
            }
            else
            {
                // To strip trailing zeros until the preferred scale is reached
                while (!BigInteger.TestBit(integerQuot, 0))
                {
                    quotient = BigMath.DivideAndRemainder(integerQuot, BigDecimal.TenPow[i], out remainder);
                    if ((remainder.Sign == 0) &&
                        (newScale - i >= diffScale))
                    {
                        newScale -= i;
                        if (i < lastPow)
                        {
                            i++;
                        }
                        integerQuot = quotient;
                    }
                    else
                    {
                        if (i == 1)
                        {
                            break;
                        }
                        i = 1;
                    }
                }
            }
            // To perform rounding
            return(new BigDecimal(integerQuot, BigDecimal.ToIntScale(newScale), mc));
        }