Exemplo n.º 1
0
        public static bool TryParse(out Double value, string s, int ichMin, int ichLim, out int ichEnd)
        {
            bool  neg = false;
            ulong num = 0;
            long  exp = 0;

            ichEnd = ichMin;
            if (!TryParseCore(s, ref ichEnd, ichLim, ref neg, ref num, ref exp))
            {
                return(TryParseSpecial(out value, s, ref ichEnd, ichLim));
            }

            if (num == 0)
            {
                value = 0;
                goto LDone;
            }

            ulong mul;
            int   e2;

            if (exp >= 0)
            {
                if (exp == 0)
                {
                    // REVIEW: casting ulong to Double doesn't always get the answer correct.
                    // Casting a non-negative long does work, though, so we jump through hoops to make
                    // sure the top bit is clear and cast to long before casting to Double.
                    if ((long)num >= 0)
                    {
                        value = (Double)(long)num;
                    }
                    else
                    {
                        value  = (Double)(long)((num >> 1) | (num & 1));
                        value += value;
                    }
                    goto LDone;
                }
                if (exp <= 22 && num < (1UL << 53))
                {
                    // Can just use Double division, since both 10^|exp| and num can be exactly represented in Double.
                    // REVIEW: there are potential other "easy" cases, like when num isn't less than 2^54, but
                    // it ends with enough zeros that it can be made so by shifting.
                    Contracts.Assert((long)(Double)(long)num == (long)num);
                    value = (Double)(long)num * _mpe10Dbl[exp - 1];
                    goto LDone;
                }
                if (exp > _mpe10Man.Length)
                {
                    value = Double.PositiveInfinity;
                    goto LDone;
                }
                int index = (int)exp - 1;
                mul = _mpe10Man[index];
                e2  = _mpe10e2[index];
            }
            else
            {
                if (-exp <= 22 && num < (1UL << 53))
                {
                    // Can just use Double division, since both 10^|exp| and num can be exactly represented in Double.
                    // REVIEW: there are potential other "easy" cases, like when num isn't less than 2^54, but
                    // it ends with enough zeros that it can be made so by shifting.
                    Contracts.Assert((long)(Double)(long)num == (long)num);
                    value = (Double)(long)num / _mpe10Dbl[-exp - 1];
                    goto LDone;
                }
                if (-exp > _mpne10Man.Length)
                {
                    value = 0;
                    goto LDone;
                }
                int index = -(int)exp - 1;
                mul = _mpne10Man[index];
                e2  = -_mpne10ne2[index];
            }

            // Normalize the mantissa and initialize the base-2 (biased) exponent.
            // Ensure that the high bit is set.
            if ((num & 0xFFFFFFFF00000000UL) == 0)
            {
                num <<= 32; e2 -= 32;
            }
            if ((num & 0xFFFF000000000000UL) == 0)
            {
                num <<= 16; e2 -= 16;
            }
            if ((num & 0xFF00000000000000UL) == 0)
            {
                num <<= 8; e2 -= 8;
            }
            if ((num & 0xF000000000000000UL) == 0)
            {
                num <<= 4; e2 -= 4;
            }
            if ((num & 0xC000000000000000UL) == 0)
            {
                num <<= 2; e2 -= 2;
            }

            // Don't force the top bit to be non-zero, since we'll just have to clear it later....
            // if ((num & 0x8000000000000000UL) == 0) { num <<= 1; e2 -= 1; }

            // The high bit of mul is 1, and at least one of the top two bits of num is non-zero.
            // Taking the high 64 bits of the 128 bit result should give us enough bits to get the
            // right answer most of the time. Note, that it's not guaranteed that we always get the
            // right answer. Guaranteeing that takes much more work.... See the paper by David Gay at
            // http://www.ampl.com/REFS/rounding.pdf.
            Contracts.Assert((num & TopTwoBits) != 0);
            Contracts.Assert((mul & TopBit) != 0);

            // Multiply mul into num, keeping the high ulong.
            // REVIEW: Can this be made faster? It would be nice to use the _umul128 intrinsic.
            ulong hi1 = mul >> 32;
            ulong lo1 = mul & 0xFFFFFFFFUL;
            ulong hi2 = num >> 32;
            ulong lo2 = num & 0xFFFFFFFFUL;

            num   = hi1 * hi2;
            hi1  *= lo2;
            hi2  *= lo1;
            num  += hi1 >> 32;
            num  += hi2 >> 32;
            hi1 <<= 32;
            hi2 <<= 32;
            if ((hi1 += hi2) < hi2)
            {
                num++;
            }
            lo1 *= lo2;
            if ((lo1 += hi1) < hi1)
            {
                num++;
            }

            // Cast to long first since ulong => Double is broken.
            Contracts.Assert((num & TopThreeBits) != 0);
            if ((long)num >= 0)
            {
                // Capture a non-zero lo to avoid an artificial tie.
                if (lo1 != 0)
                {
                    num |= 1;
                }
                value = (Double)(long)num;
            }
            else
            {
                if ((lo1 | (num & 1)) != 0)
                {
                    num |= 2;
                }
                value = (Double)(long)(num >> 1);
                e2++;
            }

            // Adjust the base-2 exponent.
            e2 += 0x3FF;
            if (e2 >= 0x7FF)
            {
                Contracts.Assert(exp > 0);
                value = Double.PositiveInfinity;
                goto LDone;
            }
            if (e2 <= 0)
            {
                // Break the exponent adjustment into two operations.
                Contracts.Assert(exp < 0);
                mul = 1UL << 52;
                unsafe { value *= *(Double *)&mul; }
                e2 += 0x3FF - 1;
                Contracts.Assert(e2 > 0);
            }

            // Multiply by the exponent adjustment.
            Contracts.Assert(0 < e2 & e2 < 0x7FF);
            mul = (ulong)e2 << 52;
            unsafe { value *= *(Double *)&mul; }

LDone:
            if (neg)
            {
                value = -value;
            }

#if COMPARE_BCL
            string str = s.Substring(ichMin, ichEnd - ichMin);
            Double x;
            if (!Double.TryParse(str, out x))
            {
                // Double.TryParse doesn't gracefully handle overflow to infinity.
                if (!Double.IsPositiveInfinity(value) && !Double.IsNegativeInfinity(value))
                {
                    if (!_failed)
                    {
                        _failed = true;
                        Contracts.Assert(false, string.Format("Double.TryParse failed on: {0}", str));
                    }
                }
            }
            else if (FloatUtils.GetBits(x) != FloatUtils.GetBits(value))
            {
                // Double.TryParse gets negative zero wrong!
                if (FloatUtils.GetBits(x) != 0 || FloatUtils.GetBits(value) != TopBit || !neg)
                {
                    System.Diagnostics.Debug.WriteLine("*** FloatParser disagrees with Double.TryParse on: {0} ({1} vs {2})", str, FloatUtils.GetBits(x), FloatUtils.GetBits(value));
                }
            }
#endif

            return(true);
        }
Exemplo n.º 2
0
        public static bool TryParse(out Single value, string s, int ichMin, int ichLim, out int ichEnd)
        {
            bool  neg = false;
            ulong num = 0;
            long  exp = 0;

            ichEnd = ichMin;
            if (!TryParseCore(s, ref ichEnd, ichLim, ref neg, ref num, ref exp))
            {
                return(TryParseSpecial(out value, s, ref ichEnd, ichLim));
            }

            if (num == 0)
            {
                value = 0;
                goto LDone;
            }

            // The Single version simply looks up the power of 10 in a table (as a Double), casts num
            // to Double, multiples, then casts to Single.
            Double res;

            if (exp >= 0)
            {
                if (exp == 0)
                {
                    res = 1;
                }
                else if (exp > _mpe10Dbl.Length)
                {
                    value = Single.PositiveInfinity;
                    goto LDone;
                }
                else
                {
                    res = _mpe10Dbl[(int)exp - 1];
                }
            }
            else
            {
                if (-exp > _mpne10Dbl.Length)
                {
                    value = 0;
                    goto LDone;
                }
                res = _mpne10Dbl[-(int)exp - 1];
            }

            // REVIEW: casting ulong to Double doesn't always get the answer correct.
            // Casting a non-negative long does work, though, so we jump through hoops to make
            // sure the top bit is clear and cast to long before casting to Double.
            Double tmp;

            if ((long)num >= 0)
            {
                tmp = (Double)(long)num;
            }
            else
            {
                tmp  = (Double)(long)((num >> 1) | (num & 1));
                tmp += tmp;
            }

            res  *= tmp;
            value = (Single)res;

LDone:
            if (neg)
            {
                value = -value;
            }

#if COMPARE_BCL
            if (!_failed)
            {
                string str = s.Substring(ichMin, ichEnd - ichMin);
                Single x;
                if (!Single.TryParse(str, out x))
                {
                    // Single.TryParse doesn't gracefully handle overflow to infinity.
                    if (!Single.IsPositiveInfinity(value) && !Single.IsNegativeInfinity(value))
                    {
                        _failed = true;
                        Contracts.Assert(false, string.Format("Single.TryParse failed on: {0}", str));
                    }
                }
                else if (FloatUtils.GetBits(x) != FloatUtils.GetBits(value))
                {
                    // Double.TryParse gets negative zero wrong!
                    if (FloatUtils.GetBits(x) != 0 || FloatUtils.GetBits(value) != 0x80000000U || !neg)
                    {
                        _failed = true;
                        Contracts.Assert(false, string.Format("FloatParser disagrees with Single.TryParse on: {0} ({1} vs {2})", str, FloatUtils.GetBits(x), FloatUtils.GetBits(value)));
                    }
                }
            }
#endif

            return(true);
        }