unsafe public void ParseNumberString_Works_Scnenarios()
        {
            Skip.If(base.NoDiffToolDetected(), "No diff tool detected");

            Dictionary <string, string> sut = new Dictionary <string, string>();

            sut.Add("leading zeros", "001");
            sut.Add("leading zeros neg", "-001");

            sut.Add("zero", "0");

            sut.Add("double", "0.00000000000000212312312");
            sut.Add("double neg", "-0.00000000000000212312312");
            sut.Add("int", "1");
            sut.Add("int neg", "-1");

            sut.Add("autreint ", "123124");
            sut.Add("autreint neg", "-123124");

            sut.Add("notation scientifique", "4.56E+2");
            sut.Add("notation scientifique neg", "-4.56E-2");

            sut.Add("notation scientifique 2", "4.5644E+2");
            sut.Add("notation scientifique 2 neg", "-4.5644E-2");

            sut.Add("notation scientifique 3", "4424.5644E+22");
            sut.Add("notation scientifique 3 neg", "-4424.5644E-22");

            sut.Add("notation scientifique 4", "4424.5644E+223");
            sut.Add("notation scientifique 4 neg", "-4424.5644E-223");
            StringBuilder sb = new StringBuilder();

            foreach (KeyValuePair <string, string> kv in sut)
            {
                sb.AppendLine($"Scenario : {kv.Key} ");
                sb.AppendLine($"Valeur   : {kv.Value} ");

                fixed(char *p = kv.Value)
                {
                    char *pend = p + kv.Value.Length;
                    var   res  = ParsedNumberString.ParseNumberString(p, pend);

                    sb.AppendLine($"Resultat : {res.exponent} {res.mantissa} {res.negative} {res.valid}");
                    sb.AppendLine();
                }
            }

            // We do not want to fail the tests when the user has not
            // configured a diff tool.
            try
            {
                VerifyData(sb.ToString());
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Example #2
0
        unsafe public void ParseNumberString_Works_Scnenarios()
        {
            Dictionary <string, string> sut = new Dictionary <string, string>();

            sut.Add("leading zeros", "001");
            sut.Add("leading zeros neg", "-001");

            sut.Add("zero", "0");
            sut.Add("zero neg", "-0");

            sut.Add("double", "0.00000000000000212312312");
            sut.Add("double neg", "-0.00000000000000212312312");
            sut.Add("int", "1");
            sut.Add("int neg", "-1");

            sut.Add("autreint ", "123124");
            sut.Add("autreint neg", "-123124");

            sut.Add("notation scientifique", "4.56E+2");
            sut.Add("notation scientifique neg", "-4.56E-2");

            sut.Add("notation scientifique 2", "4.5644E+2");
            sut.Add("notation scientifique 2 neg", "-4.5644E-2");

            sut.Add("notation scientifique 3", "4424.5644E+22");
            sut.Add("notation scientifique 3 neg", "-4424.5644E-22");

            sut.Add("notation scientifique 4", "4424.5644E+223");
            sut.Add("notation scientifique 4 neg", "-4424.5644E-223");
            StringBuilder sb = new StringBuilder();

            foreach (KeyValuePair <string, string> kv in sut)
            {
                sb.AppendLine($"Scenario : {kv.Key} ");
                sb.AppendLine($"Valeur   : {kv.Value} ");

                fixed(char *p = kv.Value)
                {
                    char *pend = p + kv.Value.Length;
                    var   res  = ParsedNumberString.ParseNumberString(p, pend);

                    sb.AppendLine($"Resultat : {res.exponent} {res.mantissa} {res.negative} {res.valid}");
                    sb.AppendLine();
                }
            }

            VerifyData(sb.ToString());
        }
        // SKIP [Benchmark(Description = "ParseNumberString() only")]
        public double FastParser_PNS()
        {
            double max = double.MinValue;

            foreach (string l in _lines)
            {
                unsafe
                {
                    fixed(char *p = l)
                    {
                        var pni = ParsedNumberString.ParseNumberString(p, p + l.Length);

                        max = pni.exponent > max ? pni.exponent : max;
                    }
                }
            }
            return(max);
        }
Example #4
0
        public static float FastPath(ParsedNumberString pns)
        {
            float value = (float)pns.mantissa;

            if (pns.exponent < 0)
            {
                value = value / exact_power_of_ten(-pns.exponent);
            }
            else
            {
                value = value * exact_power_of_ten(pns.exponent);
            }
            if (pns.negative)
            {
                value = -value;
            }
            return(value);
        }
Example #5
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));
        }
Example #6
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);
        }