[Issue 5811] New: [patch] std.conv.parse isFloatingPoint!Target doesn't parse "inf"/"-inf" with input ranges

d-bugmail at puremagic.com d-bugmail at puremagic.com
Sun Apr 3 18:02:30 PDT 2011


http://d.puremagic.com/issues/show_bug.cgi?id=5811

           Summary: [patch] std.conv.parse isFloatingPoint!Target doesn't
                    parse "inf"/"-inf" with input ranges
           Product: D
           Version: D2
          Platform: Other
        OS/Version: Windows
            Status: NEW
          Keywords: patch
          Severity: normal
          Priority: P2
         Component: Phobos
        AssignedTo: nobody at puremagic.com
        ReportedBy: sandford at jhu.edu


--- Comment #0 from Rob Jacques <sandford at jhu.edu> 2011-04-03 17:58:52 PDT ---
I ran into a problem with parse!real(r), when r was a strict input range, r
contained "inf" or "-inf" and "inf" wasn't the only item parsed from the
stream. The patch simply consists of moving inf detection from the sign
detection switch to right after the nan detection section, which I
copy/paste/modified to inf.

[Patch] DMD 2.052 (line 1301 in Github at time of posting)
Target parse(Target, Source)(ref Source p)
if (isInputRange!Source && /*!isSomeString!Source && */isFloatingPoint!Target)
{
    static immutable real negtab[14] =
        [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L,
                1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ];
    static immutable real postab[13] =
        [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L,
                1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ];
    // static immutable string infinity = "infinity";
    // static immutable string nans = "nans";

    ConvException bailOut(string f = __FILE__, size_t n = __LINE__)
        (string msg = null) {
        if (!msg) msg = "Floating point conversion error";
        return new ConvException(text(f, ":", n, ": ", msg, " for input \"", p,
"\"."));
    }

    for (;;)
    {
        enforce(!p.empty, bailOut());
        if (!isspace(p.front)) break;
        p.popFront();
    }
    char sign = 0;                       /* indicating +                 */
    switch (p.front)
    {
    case '-':
        sign++;
        p.popFront();
        enforce(!p.empty, bailOut());
        break;
    case '+':
        p.popFront();
        enforce(!p.empty, bailOut());
        break;

    default: {}
    }

    bool isHex = false;
    bool startsWithZero = p.front == '0';
    if(startsWithZero)
    {
        p.popFront();
        if(p.empty)
        {
            return (sign) ? -0 : 0;
        }

        isHex = p.front == 'x' || p.front == 'X';
    }

    real ldval = 0.0;
    char dot = 0;                        /* if decimal point has been seen */
    int exp = 0;
    long msdec = 0, lsdec = 0;
    ulong msscale = 1;

    if (isHex)
    {
        int guard = 0;
        int anydigits = 0;
        uint ndigits = 0;

        p.popFront();
        while (!p.empty)
        {
            int i = p.front;
            while (isxdigit(i))
            {
                anydigits = 1;
                i = isalpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0';
                if (ndigits < 16)
                {
                    msdec = msdec * 16 + i;
                    if (msdec)
                        ndigits++;
                }
                else if (ndigits == 16)
                {
                    while (msdec >= 0)
                    {
                        exp--;
                        msdec <<= 1;
                        i <<= 1;
                        if (i & 0x10)
                            msdec |= 1;
                    }
                    guard = i << 4;
                    ndigits++;
                    exp += 4;
                }
                else
                {
                    guard |= i;
                    exp += 4;
                }
                exp -= dot;
                p.popFront();
                if (p.empty) break;
                i = p.front;
            }
            if (i == '.' && !dot)
            {       p.popFront();
                dot = 4;
            }
            else
                break;
        }

        // Round up if (guard && (sticky || odd))
        if (guard & 0x80 && (guard & 0x7F || msdec & 1))
        {
            msdec++;
            if (msdec == 0)                 // overflow
            {   msdec = 0x8000000000000000L;
                exp++;
            }
        }

        enforce(anydigits, bailOut());
        enforce(!p.empty && (p.front == 'p' || p.front == 'P'),
                bailOut("Floating point parsing: exponent is required"));
        char sexp;
        int e;

        sexp = 0;
        p.popFront();
        if (!p.empty)
        {
            switch (p.front)
            {   case '-':    sexp++;
                case '+':    p.popFront(); enforce(!p.empty,
                        new ConvException("Error converting input"
                                " to floating point"));
                default: {}
            }
        }
        ndigits = 0;
        e = 0;
        while (!p.empty && isdigit(p.front))
        {
            if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow
            {
                e = e * 10 + p.front - '0';
            }
            p.popFront();
            ndigits = 1;
        }
        exp += (sexp) ? -e : e;
        enforce(ndigits, new ConvException("Error converting input"
                        " to floating point"));

        if (msdec)
        {
            int e2 = 0x3FFF + 63;

            // left justify mantissa
            while (msdec >= 0)
            {   msdec <<= 1;
                e2--;
            }

            // Stuff mantissa directly into real
            *cast(long *)&ldval = msdec;
            (cast(ushort *)&ldval)[4] = cast(ushort) e2;

            // Exponent is power of 2, not power of 10
            ldval = ldexpl(ldval,exp);
        }
        goto L6;
    }
    else // not hex
    {
        if (toupper(p.front) == 'N' && !startsWithZero)
        {
            // nan
            enforce((p.popFront(), !p.empty && toupper(p.front) == 'A')
                    && (p.popFront(), !p.empty && toupper(p.front) == 'N'),
                   new ConvException("error converting input to floating
point"));
            // skip past the last 'n'
            p.popFront();
            return typeof(return).nan;
        }
        if (toupper(p.front) == 'I' && !startsWithZero)
        {
            // inf
            enforce((p.popFront(), !p.empty && toupper(p.front) == 'N')
                    && (p.popFront(), !p.empty && toupper(p.front) == 'F'),
                   new ConvException("error converting input to floating
point"));
            // skip past the last 'n'
            p.popFront();
            return sign ? -Target.infinity : Target.infinity;
        }

        bool sawDigits = startsWithZero;

        while (!p.empty)
        {
            int i = p.front;
            while (isdigit(i))
            {
                sawDigits = true;        /* must have at least 1 digit   */
                if (msdec < (0x7FFFFFFFFFFFL-10)/10)
                    msdec = msdec * 10 + (i - '0');
                else if (msscale < (0xFFFFFFFF-10)/10)
                {   lsdec = lsdec * 10 + (i - '0');
                    msscale *= 10;
                }
                else
                {
                    exp++;
                }
                exp -= dot;
                p.popFront();
                if (p.empty) break;
                i = p.front;
            }
            if (i == '.' && !dot)
            {
                p.popFront();
                dot++;
            }
            else
            {
                break;
            }
        }
        enforce(sawDigits, new ConvException("no digits seen"));
    }
    if (!p.empty && (p.front == 'e' || p.front == 'E'))
    {
        char sexp;
        int e;

        sexp = 0;
        p.popFront();
        enforce(!p.empty, new ConvException("Unexpected end of input"));
        switch (p.front)
        {   case '-':    sexp++;
            case '+':    p.popFront();
            default: {}
        }
        bool sawDigits = 0;
        e = 0;
        while (!p.empty && isdigit(p.front))
        {
            if (e < 0x7FFFFFFF / 10 - 10)   // prevent integer overflow
            {
                e = e * 10 + p.front - '0';
            }
            p.popFront();
            sawDigits = 1;
        }
        exp += (sexp) ? -e : e;
        enforce(sawDigits, new ConvException("No digits seen."));
    }

    ldval = msdec;
    if (msscale != 1)               /* if stuff was accumulated in lsdec */
        ldval = ldval * msscale + lsdec;
    if (ldval)
    {
        uint u = 0;
        int pow = 4096;

        while (exp > 0)
        {
            while (exp >= pow)
            {
                ldval *= postab[u];
                exp -= pow;
            }
            pow >>= 1;
            u++;
        }
        while (exp < 0)
        {
            while (exp <= -pow)
            {
                ldval *= negtab[u];
                enforce(ldval != 0, new ConvException("Range error"));
                exp += pow;
            }
            pow >>= 1;
            u++;
        }
    }
  L6: // if overflow occurred
    enforce(ldval != core.stdc.math.HUGE_VAL, new ConvException("Range
error"));

  L1:
    return (sign) ? -ldval : ldval;
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list