[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