[svn:parrot] r39298 - branches/tt24_unicode_numifications/src/string
bacek at svn.parrot.org
bacek at svn.parrot.org
Sun May 31 22:43:27 UTC 2009
Author: bacek
Date: Sun May 31 22:43:26 2009
New Revision: 39298
URL: https://trac.parrot.org/parrot/changeset/39298
Log:
[core] Use integers in Parrot_str_to_num to preserve precision if possible
Modified:
branches/tt24_unicode_numifications/src/string/api.c
Modified: branches/tt24_unicode_numifications/src/string/api.c
==============================================================================
--- branches/tt24_unicode_numifications/src/string/api.c Sun May 31 22:05:16 2009 (r39297)
+++ branches/tt24_unicode_numifications/src/string/api.c Sun May 31 22:43:26 2009 (r39298)
@@ -2169,11 +2169,19 @@
Parrot_str_to_num(PARROT_INTERP, ARGIN(const STRING *s))
{
ASSERT_ARGS(Parrot_str_to_num)
- FLOATVAL f = 0.0;
- FLOATVAL sign = 1.0; /* -1 for '-' */
- FLOATVAL d = 0.1;
- INTVAL e = 0;
- INTVAL e_sign = 1; /* -1 for '-' */
+ FLOATVAL f = 0.0;
+ FLOATVAL mantissa = 0.0;
+ FLOATVAL sign = 1.0; /* -1 for '-' */
+ FLOATVAL divider = 0.1;
+ INTVAL e = 0;
+ INTVAL e_sign = 1; /* -1 for '-' */
+ /* How many digits it's safe to parse */
+ const INTVAL max_safe = PARROT_INTVAL_MAX / 10;
+ INTVAL m = 0; /* Integer mantissa */
+ int m_is_safe = 1; /* We can use integer mantissa */
+ INTVAL d = 0; /* Integer descriminator */
+ int d_is_safe = 1; /* We can use integer mantissa */
+ int d_length = 0;
String_iter iter;
UINTVAL offs;
number_parse_state state = parse_start;
@@ -2194,6 +2202,7 @@
case parse_start:
if (isdigit(c)) {
f = c - '0';
+ m = c - '0';
state = parse_before_dot;
}
else if (c == '-') {
@@ -2211,20 +2220,42 @@
break;
case parse_before_dot:
- if (isdigit(c))
+ if (isdigit(c)) {
f = f*10.0 + (c-'0');
- else if (c == '.')
+ m = m*10 + (c-'0');
+ /* Integer overflow for mantissa */
+ if (m > max_safe)
+ m_is_safe = 0;
+ }
+ else if (c == '.') {
state = parse_after_dot;
- else if (c == 'e' || c == 'E')
+ /*
+ * Throw gathered result. Recalulate from integer mantissa
+ * to preserve precision.
+ */
+ if (m_is_safe)
+ f = m;
+ mantissa = f;
+ }
+ else if (c == 'e' || c == 'E') {
state = parse_after_e;
+ /* See comment above */
+ if (m_is_safe)
+ f = m;
+ mantissa = f;
+ }
else
state = parse_end;
break;
case parse_after_dot:
if (isdigit(c)) {
- f += (c-'0') * d;
- d /= 10.0;
+ f += (c-'0') * divider;
+ divider /= 10.0;
+ d = d*10 + (c-'0');
+ if (d >= max_safe)
+ d_is_safe = 0;
+ d_length++;
}
else if (c == 'e' || c == 'E')
state = parse_after_e;
@@ -2261,6 +2292,10 @@
}
}
+ if (d && d_is_safe) {
+ f = mantissa + (1.0 * d / powl(10, d_length));
+ }
+
f = f * sign;
if (e_sign == 1)
f *= powl(10, e);
More information about the parrot-commits
mailing list