Exemplo n.º 1
0
        public static float ParseFloat(string s, chars_format expectedFormat = chars_format.is_general, char decimal_separator = '.')
        {
            if (s == null)
            {
                throw new ArgumentNullException(nameof(s));
            }

            unsafe
            {
                fixed(char *pStart = s)
                {
                    return(ParseFloat(pStart, pStart + s.Length, expectedFormat, decimal_separator));
                }
            }
        }
Exemplo n.º 2
0
        unsafe static internal float ParseNumber(char *first, char *last, chars_format expectedFormat = chars_format.is_general, char decimal_separator = '.')
        {
            while ((first != last) && Utils.is_space((byte)(*first)))
            {
                first++;
            }
            if (first == last)
            {
                throw new ArgumentException();
            }
            ParsedNumberString pns = ParseNumberString(first, last, expectedFormat);

            if (!pns.valid)
            {
                return(HandleInvalidInput(first, last));
            }

            // Next is Clinger's fast path.
            if (FloatBinaryConstants.min_exponent_fast_path <= pns.exponent && pns.exponent <= FloatBinaryConstants.max_exponent_fast_path && pns.mantissa <= FloatBinaryConstants.max_mantissa_fast_path && !pns.too_many_digits)
            {
                return(FastPath(pns));
            }

            AdjustedMantissa am = ComputeFloat(pns.exponent, pns.mantissa);

            if (pns.too_many_digits)
            {
                if (am != ComputeFloat(pns.exponent, pns.mantissa + 1))
                {
                    am.power2 = -1; // value is invalid.
                }
            }
            // If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa) and we have an invalid power (am.power2 < 0),
            // then we need to go the long way around again. This is very uncommon.
            if (am.power2 < 0)
            {
                am = ParseLongMantissa(first, last, decimal_separator);
            }
            return(ToFloat(pns.negative, am));
        }
Exemplo n.º 3
0
 unsafe static public float ParseFloat(char *first, char *last, chars_format expectedFormat = chars_format.is_general, char decimal_separator = '.')
 => ParseNumber(first, last, expectedFormat, decimal_separator);
Exemplo n.º 4
0
        unsafe static internal ParsedNumberString ParseNumberString(char *p, char *pend, chars_format expectedFormat = chars_format.is_general, char decimal_separator = '.')
        {
            ParsedNumberString answer = new ParsedNumberString();

            answer.valid           = false;
            answer.too_many_digits = false;
            answer.negative        = (*p == '-');
            if ((*p == '-') || (*p == '+'))
            {
                ++p;
                if (p == pend)
                {
                    return(answer);
                }
                if (!Utils.is_integer(*p) && (*p != decimal_separator)) // culture info ?
                {                                                       // a  sign must be followed by an integer or the dot
                    return(answer);
                }
            }
            char *start_digits = p;

            ulong i = 0; // an unsigned int avoids signed overflows (which are bad)

            while ((p != pend) && Utils.is_integer(*p))
            {
                // a multiplication by 10 is cheaper than an arbitrary integer
                // multiplication
                i = 10 * i +
                    (ulong)(*p - '0'); // might overflow, we will handle the overflow later
                ++p;
            }
            char *end_of_integer_part = p;
            long  digit_count         = (long)(end_of_integer_part - start_digits);
            long  exponent            = 0;

            if ((p != pend) && (*p == decimal_separator))
            {
                ++p;
                while ((p != pend) && Utils.is_integer(*p))
                {
                    byte digit = (byte)(*p - '0');
                    ++p;
                    i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
                }
                exponent     = end_of_integer_part + 1 - p;
                digit_count -= exponent;
            }
            // we must have encountered at least one integer!
            if (digit_count == 0)
            {
                return(answer);
            }
            long exp_number = 0;      // explicit exponential part

            if (expectedFormat.HasFlag(chars_format.is_scientific) && (p != pend) && (('e' == *p) || ('E' == *p)))
            {
                char *location_of_e = p;
                ++p;
                bool neg_exp = false;
                if ((p != pend) && ('-' == *p))
                {
                    neg_exp = true;
                    ++p;
                }
                else if ((p != pend) && ('+' == *p))
                {
                    ++p;
                }
                if ((p == pend) || !Utils.is_integer(*p))
                {
                    if (expectedFormat != chars_format.is_fixed)
                    {
                        // We are in error.
                        return(answer);
                    }
                    // Otherwise, we will be ignoring the 'e'.
                    p = location_of_e;
                }
                else
                {
                    while ((p != pend) && Utils.is_integer(*p))
                    {
                        byte digit = (byte)(*p - '0');
                        if (exp_number < 0x10000)
                        {
                            exp_number = 10 * exp_number + digit;
                        }
                        ++p;
                    }
                    if (neg_exp)
                    {
                        exp_number = -exp_number;
                    }
                    exponent += exp_number;
                }
            }
            else
            {
                // If it scientific and not fixed, we have to bail out.
                if ((expectedFormat.HasFlag(chars_format.is_scientific)) && !(expectedFormat.HasFlag(chars_format.is_fixed)))
                {
                    return(answer);
                }
            }
            //answer.lastmatch = p;
            answer.valid = true;

            // If we frequently had to deal with long strings of digits,
            // we could extend our code by using a 128-bit integer instead
            // of a 64-bit integer. However, this is uncommon.
            //
            // We can deal with up to 19 digits.
            if (digit_count > 19)
            { // this is uncommon
              // It is possible that the integer had an overflow.
              // We have to handle the case where we have 0.0000somenumber.
              // We need to be mindful of the case where we only have zeroes...
              // E.g., 0.000000000...000.
                char *start = start_digits;
                while ((start != pend) && (*start == '0' || *start == decimal_separator))
                {
                    if (*start == '0')
                    {
                        digit_count--;
                    }
                    start++;
                }
                if (digit_count > 19)
                {
                    answer.too_many_digits = true;
                    // Let us start again, this time, avoiding overflows.
                    i = 0;
                    p = start_digits;
                    const ulong minimal_nineteen_digit_integer = 1000000000000000000;
                    while ((i < minimal_nineteen_digit_integer) && (p != pend) && Utils.is_integer(*p))
                    {
                        i = i * 10 + (ulong)(*p - '0');
                        ++p;
                    }
                    if (i >= minimal_nineteen_digit_integer)
                    { // We have a big integers
                        exponent = end_of_integer_part - p + exp_number;
                    }
                    else
                    {        // We have a value with a fractional component.
                        p++; // skip the '.'
                        char *first_after_period = p;
                        while ((i < minimal_nineteen_digit_integer) && (p != pend) && Utils.is_integer(*p))
                        {
                            i = i * 10 + (ulong)(*p - '0');
                            ++p;
                        }
                        exponent = first_after_period - p + exp_number;
                    }
                    // We have now corrected both exponent and i, to a truncated value
                }
            }
            answer.exponent = exponent;
            answer.mantissa = i;
            return(answer);
        }