Represents an arbitrarily large signed integer.
示例#1
0
        // Helper method.
        private System.Numerics.BigInteger Convert(Jurassic.BigInteger value)
        {
            var result = System.Numerics.BigInteger.Zero;

            for (int i = value.WordCount - 1; i >= 0; i--)
            {
                result <<= 32;
                result  += value.Words[i];
            }
            if (value.Sign == -1)
            {
                result = result * -1;
            }
            return(result);
        }
示例#2
0
 /// <summary>
 /// Multiply by m and add a.
 /// </summary>
 /// <param name="b"></param>
 /// <param name="m"></param>
 /// <param name="a"></param>
 /// <returns></returns>
 public static BigInteger MultiplyAdd(BigInteger b, int m, int a)
 {
     if (m <= 0)
         throw new ArgumentOutOfRangeException("m");
     if (a < 0)
         throw new ArgumentOutOfRangeException("a");
     if (b.sign == 0)
         return new BigInteger(a);
     uint[] outputBits = new uint[b.wordCount + 1];
     int outputWordCount = b.wordCount;
     uint carry = (uint)a;
     for (int i = 0; i < b.wordCount; i++)
     {
         ulong temp = b.bits[i] * (ulong)m + carry;
         carry = (uint)(temp >> 32);
         outputBits[i] = (uint)temp;
     }
     if (carry != 0)
     {
         outputBits[outputWordCount] = carry;
         outputWordCount++;
     }
     return new BigInteger(outputBits, outputWordCount, 1);
 }
示例#3
0
        /// <summary>
        /// Shifts a BigInteger value a specified number of bits to the right.
        /// </summary>
        /// <param name="value"> The value whose bits are to be shifted. </param>
        /// <param name="shift"> The number of bits to shift <paramref name="value"/> to the right. </param>
        /// <returns> A value that has been shifted to the right by the specified number of bits.
        /// Can be negative to shift to the left. </returns>
        /// <remarks> Note: unlike System.Numerics.BigInteger, negative numbers are treated
        /// identically to positive numbers. </remarks>
        public static BigInteger RightShift(BigInteger value, int shift)
        {
            // Shifting by zero bits does nothing.
            if (shift == 0)
                return value;

            // Shifting right by a negative number of bits is the same as shifting left.
            if (shift < 0)
                return LeftShift(value, -shift);

            int wordShift = shift / 32;
            int bitShift = shift - (wordShift * 32);
            if (wordShift >= value.wordCount)
                return BigInteger.Zero;

            uint[] outputBits = new uint[value.wordCount - wordShift];
            int outputWordCount = outputBits.Length - 1;

            uint carry = 0;
            for (int i = value.wordCount - 1; i >= wordShift; i--)
            {
                uint word = value.bits[i];
                outputBits[i - wordShift] = (word >> bitShift) | (carry << (32 - bitShift));
                carry = word & (((uint)1 << bitShift) - 1);
            }
            if (outputBits[outputBits.Length - 1] != 0)
                outputWordCount++;

            return new BigInteger(outputBits, outputWordCount, value.sign);
        }
示例#4
0
        /// <summary>
        /// Shifts a BigInteger value a specified number of bits to the left.
        /// </summary>
        /// <param name="value"> The value whose bits are to be shifted. </param>
        /// <param name="shift"> The number of bits to shift <paramref name="value"/> to the left.
        /// Can be negative to shift to the right. </param>
        /// <returns> A value that has been shifted to the left by the specified number of bits. </returns>
        public static BigInteger LeftShift(BigInteger value, int shift)
        {
            // Shifting by zero bits does nothing.
            if (shift == 0)
                return value;

            // Shifting left by a negative number of bits is the same as shifting right.
            if (shift < 0)
                return RightShift(value, -shift);

            int wordShift = shift / 32;
            int bitShift = shift - (wordShift * 32);

            uint[] outputBits = new uint[value.wordCount + wordShift + 1];
            int outputWordCount = outputBits.Length - 1;

            uint carry = 0;
            for (int i = 0; i < value.wordCount; i++)
            {
                uint word = value.bits[i];
                outputBits[i + wordShift] = (word << bitShift) | carry;
                carry = bitShift == 0 ? 0 : word >> (32 - bitShift);
            }
            if (carry != 0)
            {
                outputBits[outputWordCount] = carry;
                outputWordCount++;
            }

            return new BigInteger(outputBits, outputWordCount, value.sign);
        }
示例#5
0
 /// <summary>
 /// Negates a specified BigInteger value.
 /// </summary>
 /// <param name="value"> The value to negate. </param>
 /// <returns> The result of the <paramref name="value"/> parameter multiplied by negative
 /// one (-1). </returns>
 public static BigInteger Negate(BigInteger value)
 {
     value.sign = -value.sign;
     return(value);
 }
示例#6
0
        /// <summary>
        /// Returns the logarithm of a specified number in a specified base.
        /// </summary>
        /// <param name="value"> A number whose logarithm is to be found. </param>
        /// <param name="baseValue"> The base of the logarithm. </param>
        /// <returns> The base <paramref name="baseValue"/> logarithm of <paramref name="value"/>. </returns>
        public static double Log(BigInteger value, double baseValue)
        {
            if (baseValue <= 1.0 || double.IsPositiveInfinity(baseValue) || double.IsNaN(baseValue))
                throw new ArgumentOutOfRangeException("baseValue", "Unsupported logarithmic base.");
            if (value.sign < 0)
                return double.NaN;
            if (value.sign == 0)
                return double.NegativeInfinity;
            if (value.wordCount == 1)
                return Math.Log((double)value.bits[0], baseValue);

            double d = 0.0;
            double residual = 0.5;
            int bitsInLastWord = 32 - CountLeadingZeroBits(value.bits[value.wordCount - 1]);
            int bitCount = ((value.wordCount - 1) * 32) + bitsInLastWord;
            uint highBit = ((uint)1) << (bitsInLastWord - 1);
            for (int i = value.wordCount - 1; i >= 0; i--)
            {
                while (highBit != 0)
                {
                    if ((value.bits[i] & highBit) != 0)
                        d += residual;
                    residual *= 0.5;
                    highBit = highBit >> 1;
                }
                highBit = 0x80000000;
            }
            return ((Math.Log(d) + (0.69314718055994529 * bitCount)) / Math.Log(baseValue));

        }
示例#7
0
        /// <summary>
        /// Calculates the integer result of dividing <paramref name="dividend"/> by
        /// <paramref name="divisor"/> then sets <paramref name="dividend"/> to the remainder.
        /// </summary>
        /// <param name="dividend"> The number that will be divided. </param>
        /// <param name="divisor"> The number to divide by. </param>
        /// <returns> The integer that results from dividing <paramref name="dividend"/> by
        /// <paramref name="divisor"/>. </returns>
        public static int Quorem(ref BigInteger dividend, BigInteger divisor)
        {
            int n = divisor.wordCount;
            if (dividend.wordCount > n)
                throw new ArgumentException("b is too large");
            if (dividend.wordCount < n)
                return 0;
            uint q = dividend.bits[dividend.wordCount - 1] / (divisor.bits[divisor.wordCount - 1] + 1);	/* ensure q <= true quotient */

            if (q != 0)
            {
                ulong borrow = 0;
                ulong carry = 0;
                for (int i = 0; i < divisor.wordCount; i++)
                {
                    ulong ys = divisor.bits[i] * (ulong)q + carry;
                    carry = ys >> 32;
                    ulong y = dividend.bits[i] - (ys & 0xFFFFFFFF) - borrow;
                    borrow = y >> 32 & 1;
                    dividend.bits[i] = (uint)y;
                }
                while (dividend.wordCount > 1 && dividend.bits[dividend.wordCount - 1] == 0)
                    dividend.wordCount--;
            }
            if (Compare(dividend, divisor) >= 0)
            {
                q++;
                ulong borrow = 0;
                ulong carry = 0;
                for (int i = 0; i < divisor.wordCount; i++)
                {
                    ulong ys = divisor.bits[i] + carry;
                    carry = ys >> 32;
                    ulong y = dividend.bits[i] - (ys & 0xFFFFFFFF) - borrow;
                    borrow = y >> 32 & 1;
                    dividend.bits[i] = (uint)y;
                }
                while (dividend.wordCount > 1 && dividend.bits[dividend.wordCount - 1] == 0)
                    dividend.wordCount--;
            }
            if (dividend.wordCount == 1 && dividend.bits[0] == 0)
                dividend.sign = 0;
            return (int)q;
        }
示例#8
0
 /// <summary>
 /// Negates a specified BigInteger value.
 /// </summary>
 /// <param name="value"> The value to negate. </param>
 /// <returns> The result of the <paramref name="value"/> parameter multiplied by negative
 /// one (-1). </returns>
 public static BigInteger Negate(BigInteger value)
 {
     value.sign = -value.sign;
     return value;
 }
示例#9
0
        /// <summary>
        /// Modifies the initial estimate until the closest double-precision number to the desired
        /// value is found.
        /// </summary>
        /// <param name="initialEstimate"> The initial estimate.  Assumed to be very close to the
        /// result. </param>
        /// <param name="base10Exponent"> The power-of-ten scale factor. </param>
        /// <param name="desiredValue"> The desired value, already scaled using the power-of-ten
        /// scale factor. </param>
        /// <returns> The closest double-precision number to the desired value.  If there are two
        /// such values, the one with the least significant bit set to zero is returned. </returns>
        private static double RefineEstimate(double initialEstimate, int base10Exponent, BigInteger desiredValue)
        {
            // Numbers with 16 digits or more are tricky because rounding error can cause the
            // result to be out by one or more ULPs (units in the last place).
            // The algorithm is as follows:
            // 1.  Use the initially calculated result as an estimate.
            // 2.  Create a second estimate by modifying the estimate by one ULP.
            // 3.  Calculate the actual value of both estimates to precision X (using arbitrary
            //     precision arithmetic).
            // 4.  If they are both above the desired value then decrease the estimates by 1
            //     ULP and goto step 3.
            // 5.  If they are both below the desired value then increase up the estimates by
            //     1 ULP and goto step 3.
            // 6.  One estimate must now be above the desired value and one below.
            // 7.  If one is estimate is clearly closer to the desired value than the other,
            //     then return that estimate.
            // 8.  Increase the precision by 32 bits.
            // 9.  If the precision is less than or equal to 160 bits goto step 3.
            // 10. Assume that the estimates are equally close to the desired value; return the
            //     value with the least significant bit equal to 0.
            int direction = double.IsPositiveInfinity(initialEstimate) ? -1 : 1;
            int precision = 32;

            // Calculate the candidate value by modifying the last bit.
            double result = initialEstimate;
            double result2 = AddUlps(result, direction);

            // Figure out our multiplier.  Either base10Exponent is positive, in which case we
            // multiply actual1 and actual2, or it's negative, in which case we multiply
            // desiredValue.
            BigInteger multiplier = BigInteger.One;
            if (base10Exponent < 0)
                multiplier = BigInteger.Pow(10, -base10Exponent);
            else if (base10Exponent > 0)
                desiredValue = BigInteger.Multiply(desiredValue, BigInteger.Pow(10, base10Exponent));

            while (precision <= 160)
            {
                // Scale the candidate values to a big integer.
                var actual1 = ScaleToInteger(result, multiplier, precision);
                var actual2 = ScaleToInteger(result2, multiplier, precision);

                // Calculate the differences between the candidate values and the desired value.
                var baseline = BigInteger.LeftShift(desiredValue, precision);
                var diff1 = BigInteger.Subtract(actual1, baseline);
                var diff2 = BigInteger.Subtract(actual2, baseline);

                if (diff1.Sign == direction && diff2.Sign == direction)
                {
                    // We're going the wrong way!
                    direction = -direction;
                    result2 = AddUlps(result, direction);
                }
                else if (diff1.Sign == -direction && diff2.Sign == -direction)
                {
                    // Going the right way, but need to go further.
                    result = result2;
                    result2 = AddUlps(result, direction);
                }
                else
                {
                    // Found two values that bracket the actual value.
                    // If one candidate value is closer to the actual value by at least 2 (one
                    // doesn't cut it because of the integer division) then use that value.
                    diff1 = BigInteger.Abs(diff1);
                    diff2 = BigInteger.Abs(diff2);
                    if (BigInteger.Compare(diff1, BigInteger.Subtract(diff2, BigInteger.One)) < 0)
                        return result;
                    if (BigInteger.Compare(diff2, BigInteger.Subtract(diff1, BigInteger.One)) < 0)
                        return result2;

                    // Not enough precision to determine the correct answer, or it's a halfway case.
                    // Increase the precision.
                    precision += 32;
                }

                // If result2 is NaN then we have gone too far.
                if (double.IsNaN(result2) == true)
                    return result;
            }

            // Even with heaps of precision there is no clear winner.
            // Assume this is a halfway case: choose the floating-point value with its least
            // significant bit equal to 0.
            return (XBitConverter.DoubleToInt64Bits(result) & 1) == 0 ? result : result2;
        }
示例#10
0
        /// <summary>
        /// Parses a number and returns the corresponding double-precision value.
        /// </summary>
        /// <param name="reader"> The reader to read characters from. </param>
        /// <param name="firstChar"> The first character of the number.  Must be 0-9 or a period. </param>
        /// <param name="status"> Upon returning, contains the type of error if one occurred. </param>
        /// <param name="allowHex"> </param>
        /// <param name="allowOctal"> </param>
        /// <returns> The numeric value, or <c>NaN</c> if the number is invalid. </returns>
        internal static double ParseCore(TextReader reader, char firstChar, out ParseCoreStatus status, bool allowHex = true, bool allowOctal = true)
        {
            double result;

            // A count of the number of integral and fractional digits of the input number.
            int totalDigits = 0;

            // Assume success.
            status = ParseCoreStatus.Success;

            // If the number starts with '0' then the number is a hex literal or a octal literal.
            if (firstChar == '0' && (allowHex == true || allowOctal == true))
            {
                // Read the next char - should be 'x' or 'X' if this is a hex number (could be just '0').
                int c = reader.Peek();
                if ((c == 'x' || c == 'X') && allowHex == true)
                {
                    // Hex number.
                    reader.Read();

                    result = ParseHex(reader);
                    if (double.IsNaN(result) == true)
                    {
                        status = ParseCoreStatus.InvalidHexLiteral;
                        return double.NaN;
                    }
                    status = ParseCoreStatus.HexLiteral;
                    return result;
                }
                else if (c >= '0' && c <= '9' && allowOctal == true)
                {
                    // Octal number.
                    result = ParseOctal(reader);
                    if (double.IsNaN(result) == true)
                    {
                        status = ParseCoreStatus.InvalidOctalLiteral;
                        return double.NaN;
                    }
                    status = ParseCoreStatus.OctalLiteral;
                    return result;
                }
            }

            // desired1-3 hold the integral and fractional digits of the input number.
            // desired1 holds the first set of nine digits, desired2 holds the second set of nine
            // digits, desired3 holds the rest.
            int desired1 = 0;
            int desired2 = 0;
            var desired3 = BigInteger.Zero;

            // Indicates the base-10 scale factor of the output e.g. the result is
            // desired x 10^exponentBase10.
            int exponentBase10 = 0;

            // Read the integer component.
            if (firstChar >= '0' && firstChar <= '9')
            {
                desired1 = firstChar - '0';
                totalDigits = 1;
                while (true)
                {
                    int c = reader.Peek();
                    if (c < '0' || c > '9')
                        break;
                    reader.Read();

                    if (totalDigits < 9)
                        desired1 = desired1 * 10 + (c - '0');
                    else if (totalDigits < 18)
                        desired2 = desired2 * 10 + (c - '0');
                    else
                        desired3 = BigInteger.MultiplyAdd(desired3, 10, c - '0');
                    totalDigits++;
                }
            }

            if (firstChar == '.' || reader.Peek() == '.')
            {
                // Skip past the period.
                if (firstChar != '.')
                    reader.Read();

                // Read the fractional component.
                int fractionalDigits = 0;
                while (true)
                {
                    int c = reader.Peek();
                    if (c < '0' || c > '9')
                        break;
                    reader.Read();

                    if (totalDigits < 9)
                        desired1 = desired1 * 10 + (c - '0');
                    else if (totalDigits < 18)
                        desired2 = desired2 * 10 + (c - '0');
                    else
                        desired3 = BigInteger.MultiplyAdd(desired3, 10, c - '0');
                    totalDigits++;
                    fractionalDigits++;
                    exponentBase10--;
                }

                // Check if the number consists solely of a period.
                if (totalDigits == 0)
                {
                    status = ParseCoreStatus.NoDigits;
                    return double.NaN;
                }

                // Check if the number has a period but no digits afterwards.
                if (fractionalDigits == 0)
                    status = ParseCoreStatus.NoFraction;
            }

            if (reader.Peek() == 'e' || reader.Peek() == 'E')
            {
                // Skip past the 'e'.
                reader.Read();

                // Read the sign of the exponent.
                bool exponentNegative = false;
                int c = reader.Peek();
                if (c == '+')
                    reader.Read();
                else if (c == '-')
                {
                    reader.Read();
                    exponentNegative = true;
                }

                // Read the first character of the exponent.
                int firstExponentChar = reader.Read();

                // Check there is a number after the 'e'.
                int exponent = 0;
                if (firstExponentChar < '0' || firstExponentChar > '9')
                {
                    status = ParseCoreStatus.NoExponent;
                }
                else
                {
                    // Read the rest of the exponent.
                    exponent = firstExponentChar - '0';
                    int exponentDigits = 1;
                    while (true)
                    {
                        c = reader.Peek();
                        if (c < '0' || c > '9')
                            break;
                        reader.Read();
                        exponent = Math.Min(exponent * 10 + (c - '0'), 9999);
                        exponentDigits++;
                    }

                    // JSON does not allow a leading zero in front of the exponent.
                    if (firstExponentChar == '0' && exponentDigits > 1 && status == ParseCoreStatus.Success)
                        status = ParseCoreStatus.ExponentHasLeadingZero;
                }

                // Keep track of the overall base-10 exponent.
                exponentBase10 += exponentNegative ? -exponent : exponent;
            }

            // Calculate the integral and fractional portion of the number, scaled to an integer.
            if (totalDigits < 16)
            {
                // Combine desired1 and desired2 to produce an integer representing the final
                // result.
                result = (double)((long)desired1 * integerPowersOfTen[Math.Max(totalDigits - 9, 0)] + desired2);
            }
            else
            {
                // Combine desired1, desired2 and desired3 to produce an integer representing the
                // final result.
                var temp = desired3;
                desired3 = new BigInteger((long)desired1 * integerPowersOfTen[Math.Min(totalDigits - 9, 9)] + desired2);
                if (totalDigits > 18)
                {
                    desired3 = BigInteger.Multiply(desired3, BigInteger.Pow(10, totalDigits - 18));
                    desired3 = BigInteger.Add(desired3, temp);
                }
                result = desired3.ToDouble();
            }

            // Apply the base-10 exponent.
            if (exponentBase10 > 0)
                result *= Math.Pow(10, exponentBase10);
            else if (exponentBase10 < 0 && exponentBase10 >= -308)
                result /= Math.Pow(10, -exponentBase10);
            else if (exponentBase10 < -308)
            {
                // Note: 10^308 is the largest representable power of ten.
                result /= Math.Pow(10, 308);
                result /= Math.Pow(10, -exponentBase10 - 308);
            }

            // Numbers with 16 or more digits require the use of arbitrary precision arithmetic to
            // determine the correct answer.
            if (totalDigits >= 16)
                return RefineEstimate(result, exponentBase10, desired3);

            return result;
        }
示例#11
0
 // Helper method.
 private System.Numerics.BigInteger Convert(BigInteger value)
 {
     var result = System.Numerics.BigInteger.Zero;
     for (int i = value.WordCount - 1; i >= 0; i--)
     {
         result <<= 32;
         result += value.Words[i];
     }
     if (value.Sign == -1)
         result = result * -1;
     return result;
 }
示例#12
0
        /// <summary>
        /// Converts a number to a string.
        /// </summary>
        /// <param name="value"> The value to convert to a string. </param>
        /// <param name="radix"> The base of the number system to convert to. </param>
        /// <param name="style"> The type of formatting to apply. </param>
        /// <param name="precision">
        /// This value is dependent on the formatting style:
        /// Regular - this value has no meaning.
        /// Precision - the number of significant figures to display.
        /// Fixed - the number of figures to display after the decimal point.
        /// Exponential - the number of figures to display after the decimal point.
        /// </param>
        internal static string ToString(double value, int radix, Style style, int precision = 0)
        {
            // Handle NaN.
            if (double.IsNaN(value))
                return "NaN";

            // Handle zero.
            if (value == 0.0)
            {
                switch (style)
                {
                    case Style.Regular:
                        return "0";
                    case Style.Precision:
                        return "0." + new string('0', precision - 1);
                    case Style.Fixed:
                        if (precision == 0)
                            return "0";
                        return "0." + new string('0', precision);
                    case Style.Exponential:
                        if (precision <= 0)
                            return "0e+0";
                        return string.Format("0.{0}e+0", new string('0', precision));
                }
            }

            var result = new System.Text.StringBuilder(18);

            // Handle negative numbers.
            if (value < 0.0)
            {
                value = -value;
                result.Append('-');
            }

            // Handle infinity.
            if (double.IsPositiveInfinity(value))
            {
                result.Append("Infinity");
                return result.ToString();
            }

            // Extract the base-2 exponent.
            var bits = new DoubleBits() { DoubleValue = value };
            int base2Exponent = (int)(bits.LongValue >> MantissaExplicitBits);

            // Extract the mantissa.
            long mantissa = bits.LongValue & MantissaMask;

            // Correct the base-2 exponent.
            if (base2Exponent == 0)
            {
                // This is a denormalized number.
                base2Exponent = base2Exponent - ExponentBias - MantissaExplicitBits + 1;
            }
            else
            {
                // This is a normal number.
                base2Exponent = base2Exponent - ExponentBias - MantissaExplicitBits;

                // Add the implicit bit.
                mantissa |= MantissaImplicitBit;
            }

            // Remove any trailing zeros.
            int trailingZeroBits = CountTrailingZeroBits((ulong)mantissa);
            mantissa >>= trailingZeroBits;
            base2Exponent += trailingZeroBits;

            // Calculate the logarithm of the number.
            int exponent;
            if (radix == 10)
            {
                exponent = (int)Math.Floor(Math.Log10(value));

                // We need to calculate k = floor(log10(x)).
                // log(x)	~=~ log(1.5) + (x-1.5)/1.5 (taylor series approximation)
                // log10(x) ~=~ log(1.5) / log(10) + (x - 1.5) / (1.5 * log(10))
                // d = x * 2^l (1 <= x < 2)
                // log10(d) = l * log10(2) + log10(x)
                // log10(d) ~=~ l * log10(2)           + (x - 1.5) * (1 / (1.5 * log(10)))  + log(1.5) / log(10)
                // log10(d) ~=~ l * 0.301029995663981  + (x - 1.5) * 0.289529654602168      + 0.1760912590558
                // The last term (0.1760912590558) is rounded so that k = floor(log10(x)) or
                // k = floor(log10(x)) + 1 (i.e. it's the exact value or one higher).


                //double log10;
                //if ((int)(bits.LongValue >> MantissaExplicitBits) == 0)
                //{
                //    // The number is denormalized.
                //    int mantissaShift = CountLeadingZeroBits((ulong)mantissa) - (64 - MantissaImplicitBits);
                //    bits.LongValue = (mantissa << mantissaShift) & MantissaMask |
                //        ((long)ExponentBias << MantissaExplicitBits);

                //    // Calculate an overestimate of log-10 of the value.
                //    log10 = (bits.DoubleValue - 1.5) * 0.289529654602168 + 0.1760912590558 +
                //        (base2Exponent - mantissaShift) * 0.301029995663981;
                //}
                //else
                //{
                //    // Set the base-2 exponent to biased zero.
                //    bits.LongValue = (bits.LongValue & ~ExponentMask) | ((long)ExponentBias << MantissaExplicitBits);

                //    // Calculate an overestimate of log-10 of the value.
                //    log10 = (bits.DoubleValue - 1.5) * 0.289529654602168 + 0.1760912590558 + base2Exponent * 0.301029995663981;
                //}

                //// (int)Math.Floor(log10)
                //exponent = (int)log10;
                //if (log10 < 0 && log10 != exponent)
                //    exponent--;

                //if (exponent >= 0 && exponent < tens.Length)
                //{
                //    if (value < tens[exponent])
                //        exponent--;
                //}
            }
            else
                exponent = (int)Math.Floor(Math.Log(value, radix));

            if (radix == 10 && style == Style.Regular)
            {
                // Do we have a small integer?
                if (base2Exponent >= 0 && exponent <= 14)
                {
                    // Yes.
                    for (int i = exponent; i >= 0; i--)
                    {
                        double scaleFactor = tens[i];
                        int digit = (int)(value / scaleFactor);
                        result.Append((char)(digit + '0'));
                        value -= digit * scaleFactor;
                    }
                    return result.ToString();
                }
            }

            // toFixed acts like toString() if the exponent is >= 21.
            if (style == Style.Fixed && exponent >= 21)
                style = Style.Regular;

            // Calculate the exponent thresholds.
            int lowExponentThreshold = int.MinValue;
            if (radix == 10 && style != Style.Fixed)
                lowExponentThreshold = -7;
            if (style == Style.Exponential)
                lowExponentThreshold = -1;
            int highExponentThreshold = int.MaxValue;
            if (radix == 10 && style == Style.Regular)
                highExponentThreshold = 21;
            if (style == Style.Precision)
                highExponentThreshold = precision;
            if (style == Style.Exponential)
                highExponentThreshold = 0;

            // Calculate the number of bits per digit.
            double bitsPerDigit = radix == 10 ? 3.322 : Math.Log(radix, 2);

            // Calculate the maximum number of digits to output.
            // We add 7 so that there is enough precision to distinguish halfway numbers.
            int maxDigitsToOutput = radix == 10 ? 22 : (int)Math.Floor(53 / bitsPerDigit) + 7;

            // Calculate the number of integral digits, or if negative, the number of zeros after
            // the decimal point.
            int integralDigits = exponent + 1;

            // toFixed with a low precision causes rounding.
            if (style == Style.Fixed && precision <= -integralDigits)
            {
                int diff = (-integralDigits) - (precision - 1);
                maxDigitsToOutput += diff;
                exponent += diff;
                integralDigits += diff;
            }

            // Output any leading zeros.
            bool decimalPointOutput = false;
            if (integralDigits <= 0 && integralDigits > lowExponentThreshold + 1)
            {
                result.Append('0');
                if (integralDigits < 0)
                {
                    result.Append('.');
                    decimalPointOutput = true;
                    result.Append('0', -integralDigits);
                }
            }

            // We need to calculate the integers "scaledValue" and "divisor" such that:
            // value = scaledValue / divisor * 10 ^ exponent
            // 1 <= scaledValue / divisor < 10

            BigInteger scaledValue = new BigInteger(mantissa);
            BigInteger divisor = BigInteger.One;
            BigInteger multiplier = BigInteger.One;
            if (exponent > 0)
            {
                // Number is >= 10.
                divisor = BigInteger.Multiply(divisor, BigInteger.Pow(radix, exponent));
            }
            else if (exponent < 0)
            {
                // Number is < 1.
                multiplier = BigInteger.Pow(radix, -exponent);
                scaledValue = BigInteger.Multiply(scaledValue, multiplier);
            }

            // Scale the divisor so it is 74 bits ((21 digits + 1 digit for rounding) * approx 3.322 bits per digit).
            int powerOfTwoScaleFactor = (radix == 10 ? 74 : (int)Math.Ceiling(maxDigitsToOutput * bitsPerDigit)) - divisor.BitCount;
            divisor = BigInteger.LeftShift(divisor, powerOfTwoScaleFactor);
            scaledValue = BigInteger.LeftShift(scaledValue, powerOfTwoScaleFactor + base2Exponent);

            // Calculate the error.
            BigInteger errorDelta = BigInteger.Zero;
            int errorPowerOfTen = int.MinValue;
            switch (style)
            {
                case Style.Regular:
                    errorDelta = ScaleToInteger(CalculateError(value), multiplier, powerOfTwoScaleFactor - 1);
                    break;
                case Style.Precision:
                    errorPowerOfTen = integralDigits - precision;
                    break;
                case Style.Fixed:
                    errorPowerOfTen = -precision;
                    break;
                case Style.Exponential:
                    if (precision < 0)
                        errorDelta = ScaleToInteger(CalculateError(value), multiplier, powerOfTwoScaleFactor - 1);
                    else
                        errorPowerOfTen = integralDigits - precision - 1;
                    break;
                default:
                    throw new ArgumentException("Unknown formatting style.", "style");
            }
            if (errorPowerOfTen != int.MinValue)
            {
                errorDelta = multiplier;
                if (errorPowerOfTen > 0)
                    errorDelta = BigInteger.Multiply(errorDelta, BigInteger.Pow(radix, errorPowerOfTen));
                errorDelta = BigInteger.LeftShift(errorDelta, powerOfTwoScaleFactor - 1);
                if (errorPowerOfTen < 0)
                {
                    // We would normally divide by the power of 10 here, but division is extremely
                    // slow so we multiply everything else instead.
                    //errorDelta = BigInteger.Divide(errorDelta, BigInteger.Pow(radix, -errorPowerOfTen));
                    var errorPowerOfTenMultiplier = BigInteger.Pow(radix, -errorPowerOfTen);
                    scaledValue = BigInteger.Multiply(scaledValue, errorPowerOfTenMultiplier);
                    divisor = BigInteger.Multiply(divisor, errorPowerOfTenMultiplier);
                    BigInteger.SetupQuorum(ref scaledValue, ref divisor, ref errorDelta);
                }
            }

            // Shrink the error in the case where ties are resolved towards the value with the 
            // least significant bit set to zero.
            if ((BitConverter.DoubleToInt64Bits(value) & 1) == 1)
                errorDelta.InPlaceDecrement();

            // Cache half the divisor.
            BigInteger halfDivisor = BigInteger.RightShift(divisor, 1);

            // Output the digits.
            int zeroCount = 0;
            int digitsOutput = 0;
            bool rounded = false, scientificNotation = false;
            for (; digitsOutput < maxDigitsToOutput && rounded == false; digitsOutput++)
            {
                // Calculate the next digit.
                var digit = (int)BigInteger.Quorem(ref scaledValue, divisor);

                if (BigInteger.Compare(scaledValue, errorDelta) <= 0 && BigInteger.Compare(scaledValue, halfDivisor) < 0)
                {
                    // Round down.
                    rounded = true;
                }
                else if (BigInteger.Compare(BigInteger.Subtract(divisor, scaledValue), errorDelta) <= 0)
                {
                    // Round up.
                    rounded = true;
                    digit++;
                    if (digit == radix)
                    {
                        digit = 1;
                        exponent++;
                        integralDigits++;
                    }
                }

                if (digit > 0 || decimalPointOutput == false)
                {
                    // Check if the decimal point should be output.
                    if (decimalPointOutput == false && (scientificNotation == true || digitsOutput == integralDigits))
                    {
                        result.Append('.');
                        decimalPointOutput = true;
                    }

                    // Output any pent-up zeros.
                    if (zeroCount > 0)
                    {
                        result.Append('0', zeroCount);
                        zeroCount = 0;
                    }

                    // Output the next digit.
                    if (digit < 10)
                        result.Append((char)(digit + '0'));
                    else
                        result.Append((char)(digit - 10 + 'a'));
                }
                else
                    zeroCount++;

                // Check whether the number should be displayed in scientific notation (we cannot
                // determine this up front for large exponents because the number might get rounded
                // up to cross the threshold).
                if (digitsOutput == 0 && (exponent <= lowExponentThreshold || exponent >= highExponentThreshold))
                    scientificNotation = true;

                scaledValue = BigInteger.MultiplyAdd(scaledValue, radix, 0);
                errorDelta = BigInteger.MultiplyAdd(errorDelta, radix, 0);
            }

            // Add any extra zeros on the end, if necessary.
            if (scientificNotation == false && integralDigits > digitsOutput)
            {
                result.Append('0', integralDigits - digitsOutput);
                digitsOutput = integralDigits;
            }

            // Most of the styles output redundent zeros.
            int redundentZeroCount = 0;
            switch (style)
            {
                case Style.Precision:
                    redundentZeroCount = zeroCount + precision - digitsOutput;
                    break;
                case Style.Fixed:
                    redundentZeroCount = precision - (digitsOutput - zeroCount - integralDigits);
                    break;
                case Style.Exponential:
                    redundentZeroCount = precision - (digitsOutput - zeroCount) + 1;
                    break;
            }
            if (redundentZeroCount > 0)
            {
                if (decimalPointOutput == false)
                    result.Append('.');
                result.Append('0', redundentZeroCount);
            }

            if (scientificNotation == true)
            {
                // Add the exponent on the end.
                result.Append('e');
                if (exponent > 0)
                    result.Append('+');
                result.Append(exponent);
            }

            return result.ToString();
        }
示例#13
0
 /// <summary>
 /// Gets the absolute value of a BigInteger object.
 /// </summary>
 /// <param name="value"> A number. </param>
 /// <returns> The absolute value of <paramref name="value"/> </returns>
 public static BigInteger Abs(BigInteger b)
 {
     return(new BigInteger(b.bits, b.wordCount, Math.Abs(b.sign)));
 }
示例#14
0
        /// <summary>
        /// Modifies the given values so they are suitable for passing to Quorem.
        /// </summary>
        /// <param name="dividend"> The number that will be divided. </param>
        /// <param name="divisor"> The number to divide by. </param>
        /// <param name="other"> Another value involved in the division. </param>
        public static void SetupQuorum(ref BigInteger dividend, ref BigInteger divisor, ref BigInteger other)
        {
            var leadingZeroCount = CountLeadingZeroBits(divisor.bits[divisor.wordCount - 1]);

            if (leadingZeroCount < 4 || leadingZeroCount > 28)
            {
                dividend = BigInteger.LeftShift(dividend, 8);
                divisor  = BigInteger.LeftShift(divisor, 8);
                other    = BigInteger.LeftShift(other, 8);
            }
        }
示例#15
0
        /// <summary>
        /// Computes b x 5 ^ k.
        /// </summary>
        /// <param name="b"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static BigInteger MultiplyPow5(BigInteger b, int k)
        {
            BigInteger p5;

            // Fast route if k <= 3.
            if ((k & 3) != 0)
                b = MultiplyAdd(b, powersOfFive[(k & 3) - 1], 0);
            if ((k >>= 2) == 0)
                return b;

            p5 = new BigInteger(625);
            while (true)
            {
                if ((k & 1) == 1)
                    b = Multiply(b, p5);
                if ((k >>= 1) == 0)
                    break;
                p5 = Multiply(p5, p5);
            }
            return b;
        }
示例#16
0
 /// <summary>
 /// Returns <c>-1</c> if a &lt; b, <c>0</c> if they are the same, or <c>1</c> if a &gt; b.
 /// </summary>
 /// <param name="a"></param>
 /// <param name="b"></param>
 /// <returns></returns>
 public static int Compare(BigInteger a, BigInteger b)
 {
     if (a.sign != b.sign)
         return a.sign < b.sign ? -1 : 1;
     if (a.sign > 0)
     {
         // Comparison of positive numbers.
         if (a.wordCount < b.wordCount)
             return -1;
         if (a.wordCount > b.wordCount)
             return 1;
         for (int i = a.wordCount - 1; i >= 0; i--)
         {
             if (a.bits[i] != b.bits[i])
                 return a.bits[i] < b.bits[i] ? -1 : 1;
         }
     }
     else if (a.sign < 0)
     {
         // Comparison of negative numbers.
         if (a.wordCount < b.wordCount)
             return 1;
         if (a.wordCount > b.wordCount)
             return -1;
         for (int i = a.wordCount - 1; i >= 0; i--)
         {
             if (a.bits[i] != b.bits[i])
                 return a.bits[i] < b.bits[i] ? 1 : -1;
         }
     }
     return 0;
 }
示例#17
0
        /// <summary>
        /// Scales the given double-precision number by multiplying and then shifting it.
        /// </summary>
        /// <param name="value"> The value to scale. </param>
        /// <param name="multiplier"> The multiplier. </param>
        /// <param name="shift"> The power of two scale factor. </param>
        /// <returns> A BigInteger containing the result of multiplying <paramref name="value"/> by
        /// <paramref name="multiplier"/> and then shifting left by <paramref name="shift"/> bits. </returns>
        private static BigInteger ScaleToInteger(double value, BigInteger multiplier, int shift)
        {
            long bits = XBitConverter.DoubleToInt64Bits(value);

            // Extract the base-2 exponent.
            var base2Exponent = (int)((bits & 0x7FF0000000000000) >> 52) - 1023;

            // Extract the mantissa.
            long mantissa = bits & 0xFFFFFFFFFFFFF;
            if (base2Exponent > -1023)
            {
                mantissa |= 0x10000000000000;
                base2Exponent -= 52;
            }
            else
            {
                // Denormals.
                base2Exponent -= 51;
            }

            // Extract the sign bit.
            if (bits < 0)
                mantissa = -mantissa;

            var result = new BigInteger(mantissa);
            result = BigInteger.Multiply(result, multiplier);
            shift += base2Exponent;
            result = BigInteger.LeftShift(result, shift);
            return result;
        }
示例#18
0
 /// <summary>
 /// Modifies the given values so they are suitable for passing to Quorem.
 /// </summary>
 /// <param name="dividend"> The number that will be divided. </param>
 /// <param name="divisor"> The number to divide by. </param>
 /// <param name="other"> Another value involved in the division. </param>
 public static void SetupQuorum(ref BigInteger dividend, ref BigInteger divisor, ref BigInteger other)
 {
     var leadingZeroCount = CountLeadingZeroBits(divisor.bits[divisor.wordCount - 1]);
     if (leadingZeroCount < 4 || leadingZeroCount > 28)
     {
         dividend = BigInteger.LeftShift(dividend, 8);
         divisor = BigInteger.LeftShift(divisor, 8);
         other = BigInteger.LeftShift(other, 8);
     }
 }
示例#19
0
        /// <summary>
        /// Returns the product of two BigInteger values.
        /// </summary>
        /// <param name="left"> The first number to multiply. </param>
        /// <param name="right"> The second number to multiply. </param>
        /// <returns> The product of the <paramref name="left"/> and <paramref name="right"/>
        /// parameters. </returns>
        public static BigInteger Multiply(BigInteger left, BigInteger right)
        {
            // Check for special cases.
            if (left.wordCount == 1)
            {
                // 0 * right = 0
                if (left.bits[0] == 0)
                    return BigInteger.Zero;

                // 1 * right = right
                // -1 * right = -right
                if (left.bits[0] == 1)
                    return left.sign == -1 ? Negate(right) : right;
            }
            if (right.wordCount == 1)
            {
                // left * 0 = 0
                if (right.bits[0] == 0)
                    return BigInteger.Zero;

                // left * 1 = left
                // left * -1 = -left
                if (right.bits[0] == 1)
                    return right.sign == -1 ? Negate(left) : left;
            }

            uint[] outputBits = new uint[left.wordCount + right.wordCount];
            int outputWordCount = left.wordCount + right.wordCount - 1;

            for (int i = 0; i < left.wordCount; i++)
            {
                uint carry = 0;
                for (int j = 0; j < right.wordCount; j++)
                {
                    ulong temp = (ulong)left.bits[i] * right.bits[j] + outputBits[i + j] + carry;
                    carry = (uint)(temp >> 32);
                    outputBits[i + j] = (uint)temp;
                }
                if (carry != 0)
                {
                    outputWordCount = Math.Max(outputWordCount, i + right.wordCount + 1);
                    outputBits[i + right.wordCount] = (uint)carry;
                }
            }

            while (outputWordCount > 1 && outputBits[outputWordCount - 1] == 0)
                outputWordCount--;

            return new BigInteger(outputBits, outputWordCount, left.sign * right.sign);
        }
示例#20
0
 /// <summary>
 /// Gets the absolute value of a BigInteger object.
 /// </summary>
 /// <param name="value"> A number. </param>
 /// <returns> The absolute value of <paramref name="value"/> </returns>
 public static BigInteger Abs(BigInteger b)
 {
     return new BigInteger(b.bits, b.wordCount, Math.Abs(b.sign));
 }
示例#21
0
        /// <summary>
        /// Subtracts one BigInteger value from another and returns the result.
        /// </summary>
        /// <param name="left"> The value to subtract from. </param>
        /// <param name="right"> The value to subtract. </param>
        /// <returns> The result of subtracting <paramref name="right"/> from
        /// <paramref name="left"/>. </returns>
        public static BigInteger Subtract(BigInteger left, BigInteger right)
        {
            // 0 - right = -right
            if (left.Sign == 0)
                return Negate(right);
            
            // left - 0 = left
            if (right.Sign == 0)
                return left;

            // If the signs of the two numbers are different, do an add instead.
            if (left.Sign != right.Sign)
                return Add(left, Negate(right));

            // From here the sign of both numbers is the same.
            uint[] outputBits = new uint[Math.Max(left.wordCount, right.wordCount)];
            int outputWordCount = outputBits.Length;
            int outputSign = left.sign;
            int i;

            // Arrange it so that Abs(a) > Abs(b).
            bool swap = false;
            if (left.wordCount < right.wordCount)
                swap = true;
            else if (left.wordCount == right.wordCount)
            {
                for (i = left.wordCount - 1; i >= 0; i--)
                    if (left.bits[i] != right.bits[i])
                    {
                        if (left.bits[i] < right.bits[i])
                            swap = true;
                        break;
                    }
            }
            if (swap == true)
            {
                var temp = left;
                left = right;
                right = temp;
                outputSign = -outputSign;
            }

            ulong y, borrow = 0;
            for (i = 0; i < right.wordCount; i++)
            {
                y = (ulong)left.bits[i] - right.bits[i] - borrow;
                borrow = y >> 32 & 1;
                outputBits[i] = (uint)y;
            }
            for (; i < left.wordCount; i++)
            {
                y = (ulong)left.bits[i] - borrow;
                borrow = y >> 32 & 1;
                outputBits[i] = (uint)y;
            }
            while (outputWordCount > 1 && outputBits[outputWordCount - 1] == 0)
                outputWordCount--;
            return new BigInteger(outputBits, outputWordCount, outputSign);
        }
示例#22
0
        /// <summary>
        /// Adds two BigInteger values and returns the result.
        /// </summary>
        /// <param name="left"> The first value to add. </param>
        /// <param name="right"> The second value to add. </param>
        /// <returns> The sum of <paramref name="left"/> and <paramref name="right"/>. </returns>
        public static BigInteger Add(BigInteger left, BigInteger right)
        {
            // 0 + right = right
            if (left.Sign == 0)
                return right;
            
            // left + 0 = left
            if (right.Sign == 0)
                return left;

            // If the signs of the two numbers are different, do a subtract instead.
            if (left.Sign != right.Sign)
                return Subtract(left, Negate(right));

            // From here the sign of both numbers is the same.
            int outputWordCount = Math.Max(left.wordCount, right.wordCount);
            uint[] outputBits = new uint[outputWordCount + 1];

            uint borrow = 0;
            int i = 0;
            for (; i < Math.Min(left.wordCount, right.wordCount); i++)
            {
                ulong temp = (ulong)left.bits[i] + right.bits[i] + borrow;
                borrow = (uint)(temp >> 32);
                outputBits[i] = (uint)temp;
            }
            if (left.wordCount > right.wordCount)
            {
                for (; i < left.wordCount; i++)
                {
                    ulong temp = (ulong)left.bits[i] + borrow;
                    borrow = (uint)(temp >> 32);
                    outputBits[i] = (uint)temp;
                }
            }
            else if (left.wordCount < right.wordCount)
            {
                for (; i < right.wordCount; i++)
                {
                    ulong temp = (ulong)right.bits[i] + borrow;
                    borrow = (uint)(temp >> 32);
                    outputBits[i] = (uint)temp;
                }
            }
            if (borrow != 0)
            {
                outputBits[outputWordCount] = borrow;
                outputWordCount++;
            }
            return new BigInteger(outputBits, outputWordCount, left.Sign);
        }
示例#23
0
        /// <summary>
        /// Subtracts one BigInteger value from another and returns the result.
        /// </summary>
        /// <param name="left"> The value to subtract from. </param>
        /// <param name="right"> The value to subtract. </param>
        /// <returns> The result of subtracting <paramref name="right"/> from
        /// <paramref name="left"/>. </returns>
        public static BigInteger Subtract(BigInteger left, BigInteger right)
        {
            // 0 - right = -right
            if (left.Sign == 0)
            {
                return(Negate(right));
            }

            // left - 0 = left
            if (right.Sign == 0)
            {
                return(left);
            }

            // If the signs of the two numbers are different, do an add instead.
            if (left.Sign != right.Sign)
            {
                return(Add(left, Negate(right)));
            }

            // From here the sign of both numbers is the same.
            uint[] outputBits      = new uint[Math.Max(left.wordCount, right.wordCount)];
            int    outputWordCount = outputBits.Length;
            int    outputSign      = left.sign;
            int    i;

            // Arrange it so that Abs(a) > Abs(b).
            bool swap = false;

            if (left.wordCount < right.wordCount)
            {
                swap = true;
            }
            else if (left.wordCount == right.wordCount)
            {
                for (i = left.wordCount - 1; i >= 0; i--)
                {
                    if (left.bits[i] != right.bits[i])
                    {
                        if (left.bits[i] < right.bits[i])
                        {
                            swap = true;
                        }
                        break;
                    }
                }
            }
            if (swap == true)
            {
                var temp = left;
                left       = right;
                right      = temp;
                outputSign = -outputSign;
            }

            ulong y, borrow = 0;

            for (i = 0; i < right.wordCount; i++)
            {
                y             = (ulong)left.bits[i] - right.bits[i] - borrow;
                borrow        = y >> 32 & 1;
                outputBits[i] = (uint)y;
            }
            for (; i < left.wordCount; i++)
            {
                y             = (ulong)left.bits[i] - borrow;
                borrow        = y >> 32 & 1;
                outputBits[i] = (uint)y;
            }
            while (outputWordCount > 1 && outputBits[outputWordCount - 1] == 0)
            {
                outputWordCount--;
            }
            return(new BigInteger(outputBits, outputWordCount, outputSign));
        }