ToDouble() public method

Returns a double that corresponds to the BigInteger value.
public ToDouble ( ) : double
return double
Beispiel #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;
        }
        /// <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);
        }