Jurassic.BigInteger.ToDouble C# (CSharp) Method

ToDouble() public method

Returns a double that corresponds to the BigInteger value.
public ToDouble ( ) : double
return double
        public double ToDouble()
        {
            // Special case: zero.
            if (this.wordCount == 1 && this.bits[0] == 0)
                return 0.0;

            // Get the number of bits in the BigInteger.
            var bitCount = this.BitCount;

            // The top 53 bits can be packed into the double (the top-most bit is implied).
            var temp = BigInteger.RightShift(this, bitCount - 53);
            ulong doubleBits = (((ulong)temp.bits[1] << 32) | temp.bits[0]) & 0xFFFFFFFFFFFFF;

            // Base-2 exponent is however much we shifted, plus 52 (because the decimal point is
            // effectively at the 52nd bit), plus 1023 (the bias).
            int biasedExponent = bitCount - 53 + 52 + 1023;

            // The biased exponent must be between 0 and 2047, since there are 11 bits available,
            // otherwise bad things happen.
            if (biasedExponent >= 2048)
                return double.PositiveInfinity;

            // Move the exponent to the right position.
            doubleBits |= (ulong)(biasedExponent) << 52;

            // Handle the sign bit.
            if (this.sign == -1)
                doubleBits |= (ulong)1 << 63;

            // Convert the bit representation to a double.
            return BitConverter.Int64BitsToDouble((long)doubleBits);
        }

Usage Example

示例#1
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;
        }
All Usage Examples Of Jurassic.BigInteger::ToDouble