*/
/*
-=head1 Numeric functions
-
-=cut
This file contains all the stuff needed by perl for manipulating numeric
values, including such things as replacements for the OS's atof() function
{
NV result;
- char ** end_ptr = NULL;
+ char * end_ptr;
- *end_ptr = my_atof2(s, &result);
+ end_ptr = my_atof2(s, &result);
if (e) {
- *e = *end_ptr;
+ *e = end_ptr;
}
- if (! *end_ptr) {
+ if (! end_ptr) {
result = 0.0;
}
Not documented yet because experimental is C<PERL_SCAN_SILENT_NON_PORTABLE>
which suppresses any message for non-portable numbers, but which are valid
-on this platform.
+on this platform. But, C<*flags> will have the corresponding flag bit set.
*/
UV
digits may be separated from each other by a single underscore; also a single
leading underscore is accepted.
-The the C<PERL_SCAN_DISALLOW_PREFIX> flag is always treated as being set for
+The C<PERL_SCAN_DISALLOW_PREFIX> flag is always treated as being set for
this function.
=cut
/* In overflows, this keeps track of how much to multiply the overflowed NV
* by as we continue to parse the remaining digits */
- UV factor;
+ NV factor = 0;
/* This function unifies the core of grok_bin, grok_oct, and grok_hex. It
* is optimized for hex conversion. For example, it uses XDIGIT_VALUE to
s = s0; /* s0 potentially advanced from 'start' */
/* Unroll the loop so that the first 8 digits are branchless except for the
- * switch. A ninth one overflows a 32 bit word. */
+ * switch. A ninth hex one overflows a 32 bit word. */
switch (len) {
case 0:
return 0;
default:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
s++;
/* FALLTHROUGH */
case 7:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
s++;
/* FALLTHROUGH */
case 6:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
s++;
/* FALLTHROUGH */
case 5:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
s++;
/* FALLTHROUGH */
case 4:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
s++;
/* FALLTHROUGH */
case 3:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
s++;
/* FALLTHROUGH */
case 2:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
s++;
/* FALLTHROUGH */
case 1:
- if (! _generic_isCC(*s, class_bit)) break;
+ if (UNLIKELY(! _generic_isCC(*s, class_bit))) break;
value = (value << shift) | XDIGIT_VALUE(*s);
if (LIKELY(len <= 8)) {
/* Note XDIGIT_VALUE() is branchless, works on binary
* and octal as well, so can be used here, without
* slowing those down */
- factor <<= shift;
+ factor *= 1 << shift;
continue;
}
* value. Each time through the loop we have increased 'factor' so
* that it gives how much the current approximation needs to
* effectively be shifted to make room for this new value */
- value_nv *= (NV) factor;
+ value_nv *= factor;
value_nv += (NV) value;
/* Then we keep accumulating digits, until all are parsed. We
if (! overflowed) {
overflowed = TRUE;
- Perl_ck_warner_d(aTHX_ packWARN(WARN_OVERFLOW),
+ if ( ! (input_flags & PERL_SCAN_SILENT_OVERFLOW)
+ && ckWARN_d(WARN_OVERFLOW))
+ {
+ Perl_warner(aTHX_ packWARN(WARN_OVERFLOW),
"Integer overflow in %s number",
(base == 16) ? "hexadecimal"
: (base == 2)
? "binary"
: "octal");
+ }
}
continue;
}
if ( *s == '_'
&& len
&& allow_underscores
- && _generic_isCC(s[1], class_bit))
+ && _generic_isCC(s[1], class_bit)
+
+ /* Don't allow a leading underscore if the only-medial bit is
+ * set */
+ && ( LIKELY(s > s0)
+ || UNLIKELY((input_flags & PERL_SCAN_ALLOW_MEDIAL_UNDERSCORES)
+ != PERL_SCAN_ALLOW_MEDIAL_UNDERSCORES)))
{
--len;
++s;
goto redo;
}
- if ( *s
- && ! (input_flags & PERL_SCAN_SILENT_ILLDIGIT)
- && ckWARN(WARN_DIGIT))
- {
- if (base != 8) {
- Perl_warner(aTHX_ packWARN(WARN_DIGIT),
- "Illegal %s digit '%c' ignored",
- ((base == 2)
- ? "binary"
- : "hexadecimal"),
- *s);
- }
- else if (isDIGIT(*s)) { /* octal base */
-
- /* Allow \octal to work the DWIM way (that is, stop scanning as
- * soon as non-octal characters are seen, complain only if
- * someone seems to want to use the digits eight and nine.
- * Since we know it is not octal, then if isDIGIT, must be an 8
- * or 9). */
- Perl_warner(aTHX_ packWARN(WARN_DIGIT),
+ if (*s) {
+ if ( ! (input_flags & PERL_SCAN_SILENT_ILLDIGIT)
+ && ckWARN(WARN_DIGIT))
+ {
+ if (base != 8) {
+ Perl_warner(aTHX_ packWARN(WARN_DIGIT),
+ "Illegal %s digit '%c' ignored",
+ ((base == 2)
+ ? "binary"
+ : "hexadecimal"),
+ *s);
+ }
+ else if (isDIGIT(*s)) { /* octal base */
+
+ /* Allow \octal to work the DWIM way (that is, stop
+ * scanning as soon as non-octal characters are seen,
+ * complain only if someone seems to want to use the digits
+ * eight and nine. Since we know it is not octal, then if
+ * isDIGIT, must be an 8 or 9). */
+ Perl_warner(aTHX_ packWARN(WARN_DIGIT),
"Illegal octal digit '%c' ignored", *s);
+ }
+ }
+
+ if (input_flags & PERL_SCAN_NOTIFY_ILLDIGIT) {
+ *flags |= PERL_SCAN_NOTIFY_ILLDIGIT;
}
}
&& ! (input_flags & PERL_SCAN_SILENT_NON_PORTABLE))
{
output_non_portable(base);
+ *flags |= PERL_SCAN_SILENT_NON_PORTABLE;
}
#endif
return value;
}
/* Overflowed: Calculate the final overflow approximation */
- value_nv *= (NV) factor;
+ value_nv *= factor;
value_nv += (NV) value;
output_non_portable(base);
- *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
+ *flags |= PERL_SCAN_GREATER_THAN_UV_MAX
+ | PERL_SCAN_SILENT_NON_PORTABLE;
if (result)
*result = value_nv;
return UV_MAX;
one byte past the end of the recognized string. If the recognition fails,
zero is returned, and C<*sp> will not move.
-=for apidoc Amn|bool|IS_NUMBER_GREATER_THAN_UV_MAX
-=for apidoc Amn|bool|IS_NUMBER_INFINITY
-=for apidoc Amn|bool|IS_NUMBER_IN_UV
-=for apidoc Amn|bool|IS_NUMBER_NAN
-=for apidoc Amn|bool|IS_NUMBER_NEG
-=for apidoc Amn|bool|IS_NUMBER_NOT_INT
+=for apidoc Amnh|bool|IS_NUMBER_GREATER_THAN_UV_MAX
+=for apidoc Amnh|bool|IS_NUMBER_INFINITY
+=for apidoc Amnh|bool|IS_NUMBER_IN_UV
+=for apidoc Amnh|bool|IS_NUMBER_NAN
+=for apidoc Amnh|bool|IS_NUMBER_NEG
+=for apidoc Amnh|bool|IS_NUMBER_NOT_INT
=cut
*/
s++; if (s == send || isALPHA_FOLD_NE(*s, 'N')) return 0;
s++; if (s == send) return 0;
if (isALPHA_FOLD_EQ(*s, 'F')) {
- s++;
+ flags |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT;
+ *sp = ++s;
if (s < send && (isALPHA_FOLD_EQ(*s, 'I'))) {
- int fail =
- flags | IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT | IS_NUMBER_TRAILING;
- s++; if (s == send || isALPHA_FOLD_NE(*s, 'N')) return fail;
- s++; if (s == send || isALPHA_FOLD_NE(*s, 'I')) return fail;
- s++; if (s == send || isALPHA_FOLD_NE(*s, 'T')) return fail;
- s++; if (s == send || isALPHA_FOLD_NE(*s, 'Y')) return fail;
- s++;
+ int trail = flags | IS_NUMBER_TRAILING;
+ s++; if (s == send || isALPHA_FOLD_NE(*s, 'N')) return trail;
+ s++; if (s == send || isALPHA_FOLD_NE(*s, 'I')) return trail;
+ s++; if (s == send || isALPHA_FOLD_NE(*s, 'T')) return trail;
+ s++; if (s == send || isALPHA_FOLD_NE(*s, 'Y')) return trail;
+ *sp = ++s;
} else if (odh) {
- while (*s == '0') { /* 1.#INF00 */
+ while (s < send && *s == '0') { /* 1.#INF00 */
s++;
}
}
- while (s < send && isSPACE(*s))
- s++;
- if (s < send && *s) {
- flags |= IS_NUMBER_TRAILING;
- }
- flags |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT;
+ goto ok_check_space;
}
else if (isALPHA_FOLD_EQ(*s, 'D') && odh) { /* 1.#IND */
s++;
flags |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT;
- while (*s == '0') { /* 1.#IND00 */
+ while (s < send && *s == '0') { /* 1.#IND00 */
s++;
}
- if (*s) {
- flags |= IS_NUMBER_TRAILING;
- }
+ goto ok_check_space;
} else
return 0;
}
if (isALPHA_FOLD_EQ(*s, 'N')) {
s++; if (s == send || isALPHA_FOLD_NE(*s, 'A')) return 0;
s++; if (s == send || isALPHA_FOLD_NE(*s, 'N')) return 0;
- s++;
-
flags |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT;
+ *sp = ++s;
+
if (s == send) {
return flags;
}
isALPHA_FOLD_EQ(*s, 's')) {
/* "nanq" or "nans" are ok, though generating
* these portably is tricky. */
- s++;
+ *sp = ++s;
if (s == send) {
return flags;
}
if (*s == '(') {
/* C99 style "nan(123)" or Perlish equivalent "nan($uv)". */
const char *t;
+ int trail = flags | IS_NUMBER_TRAILING;
s++;
- if (s == send) {
- return flags | IS_NUMBER_TRAILING;
- }
+ if (s == send) { return trail; }
t = s + 1;
while (t < send && *t && *t != ')') {
t++;
}
- if (t == send) {
- return flags | IS_NUMBER_TRAILING;
- }
+ if (t == send) { return trail; }
if (*t == ')') {
int nantype;
UV nanval;
* be "trailing", so we need to double-check
* whether we had something dubious. */
for (u = s; u < t; u++) {
- if (!isDIGIT(*u)) {
- flags |= IS_NUMBER_TRAILING;
+ if (!isDIGIT(*u))
break;
- }
}
s = u;
}
/* XXX Doesn't do octal: nan("0123").
* Probably not a big loss. */
+ /* XXX the nanval is currently unused, that is,
+ * not inserted as the NaN payload of the NV.
+ * But the above code already parses the C99
+ * nan(...) format. See below, and see also
+ * the nan() in POSIX.xs.
+ *
+ * Certain configuration combinations where
+ * NVSIZE is greater than UVSIZE mean that
+ * a single UV cannot contain all the possible
+ * NaN payload bits. There would need to be
+ * some more generic syntax than "nan($uv)".
+ *
+ * Issues to keep in mind:
+ *
+ * (1) In most common cases there would
+ * not be an integral number of bytes that
+ * could be set, only a certain number of bits.
+ * For example for the common case of
+ * NVSIZE == UVSIZE == 8 there is room for 52
+ * bits in the payload, but the most significant
+ * bit is commonly reserved for the
+ * signaling/quiet bit, leaving 51 bits.
+ * Furthermore, the C99 nan() is supposed
+ * to generate quiet NaNs, so it is doubtful
+ * whether it should be able to generate
+ * signaling NaNs. For the x86 80-bit doubles
+ * (if building a long double Perl) there would
+ * be 62 bits (s/q bit being the 63rd).
+ *
+ * (2) Endianness of the payload bits. If the
+ * payload is specified as an UV, the low-order
+ * bits of the UV are naturally little-endianed
+ * (rightmost) bits of the payload. The endianness
+ * of UVs and NVs can be different. */
+
if ((nantype & IS_NUMBER_NOT_INT) ||
!(nantype && IS_NUMBER_IN_UV)) {
- /* XXX the nanval is currently unused, that is,
- * not inserted as the NaN payload of the NV.
- * But the above code already parses the C99
- * nan(...) format. See below, and see also
- * the nan() in POSIX.xs.
- *
- * Certain configuration combinations where
- * NVSIZE is greater than UVSIZE mean that
- * a single UV cannot contain all the possible
- * NaN payload bits. There would need to be
- * some more generic syntax than "nan($uv)".
- *
- * Issues to keep in mind:
- *
- * (1) In most common cases there would
- * not be an integral number of bytes that
- * could be set, only a certain number of bits.
- * For example for the common case of
- * NVSIZE == UVSIZE == 8 there is room for 52
- * bits in the payload, but the most significant
- * bit is commonly reserved for the
- * signaling/quiet bit, leaving 51 bits.
- * Furthermore, the C99 nan() is supposed
- * to generate quiet NaNs, so it is doubtful
- * whether it should be able to generate
- * signaling NaNs. For the x86 80-bit doubles
- * (if building a long double Perl) there would
- * be 62 bits (s/q bit being the 63rd).
- *
- * (2) Endianness of the payload bits. If the
- * payload is specified as an UV, the low-order
- * bits of the UV are naturally little-endianed
- * (rightmost) bits of the payload. The endianness
- * of UVs and NVs can be different. */
- return 0;
+ /* treat "NaN(invalid)" the same as "NaNgarbage" */
+ return trail;
}
- if (s < t) {
- flags |= IS_NUMBER_TRAILING;
+ else {
+ /* allow whitespace between valid payload and ')' */
+ while (s < t && isSPACE(*s))
+ s++;
+ /* but on anything else treat the whole '(...)' chunk
+ * as trailing garbage */
+ if (s < t)
+ return trail;
+ s = t + 1;
+ goto ok_check_space;
}
} else {
/* Looked like nan(...), but no close paren. */
- flags |= IS_NUMBER_TRAILING;
+ return trail;
}
} else {
- while (s < send && isSPACE(*s))
- s++;
- if (s < send && *s) {
- /* Note that we here implicitly accept (parse as
- * "nan", but with warnings) also any other weird
- * trailing stuff for "nan". In the above we just
- * check that if we got the C99-style "nan(...)",
- * the "..." looks sane.
- * If in future we accept more ways of specifying
- * the nan payload, the accepting would happen around
- * here. */
- flags |= IS_NUMBER_TRAILING;
- }
+ /* Note that we here implicitly accept (parse as
+ * "nan", but with warnings) also any other weird
+ * trailing stuff for "nan". In the above we just
+ * check that if we got the C99-style "nan(...)",
+ * the "..." looks sane.
+ * If in future we accept more ways of specifying
+ * the nan payload, the accepting would happen around
+ * here. */
+ goto ok_check_space;
}
- s = send;
}
else
return 0;
}
+ NOT_REACHED; /* NOTREACHED */
+ /* We parsed something valid, s points after it, flags describes it */
+ ok_check_space:
while (s < send && isSPACE(*s))
s++;
+ *sp = s;
+ return flags | (s < send ? IS_NUMBER_TRAILING : 0);
#else
PERL_UNUSED_ARG(send);
-#endif /* #if defined(NV_INF) || defined(NV_NAN) */
*sp = s;
return flags;
+#endif /* #if defined(NV_INF) || defined(NV_NAN) */
}
/*
C<IS_NUMBER_NOT_INT> will be set with C<IS_NUMBER_IN_UV> if trailing decimals were
seen (in which case C<*valuep> gives the true value truncated to an integer), and
C<IS_NUMBER_NEG> if the number is negative (in which case C<*valuep> holds the
-absolute value). C<IS_NUMBER_IN_UV> is not set if e notation was used or the
+absolute value). C<IS_NUMBER_IN_UV> is not set if C<e> notation was used or the
number is larger than a UV.
C<flags> allows only C<PERL_SCAN_TRAILING>, which allows for trailing
* belong in a number at all (unless it's a radix character in a weird
* locale). Given this, it's far more likely to be a minus than the
* others. (On EBCDIC it is one of 42, 44, 46, 48, 4A, 4C, 4E, (not 40
- * because can't be a space) 60, 62, 64, 66, 68, 6A, 6C, 6E. Again, only
- * potentially a weird radix character, or 4E='+', or 60='-') */
+ * because can't be a space) 60, 62, 64, 66, 68, 6A, 6C, 6E. Again,
+ * only potentially a weird radix character, or 4E='+', or 60='-') */
if (LIKELY(*s == '-')) {
s++;
numtype = IS_NUMBER_NEG;
/* Really detect inf/nan. Start at d, not s, since the above
* code might have already consumed the "1." or "1". */
const int infnan = Perl_grok_infnan(aTHX_ &d, send);
+
+ if ((infnan & IS_NUMBER_TRAILING) && !(flags & PERL_SCAN_TRAILING)) {
+ return 0;
+ }
if ((infnan & IS_NUMBER_INFINITY)) {
return (numtype | infnan); /* Keep sign for infinity. */
}
passing a non-NULL C<endptr>), and if the intial bytes of that portion form a
valid value, it will return TRUE, setting C<*endptr> to the byte following the
final digit of the value. But if there is no constraint at what's looked at,
-all of C<pv> must be valid in order for TRUE to be returned.
+all of C<pv> must be valid in order for TRUE to be returned. C<*endptr> is
+unchanged from its value on input if FALSE is returned;
The only characters this accepts are the decimal digits '0'..'9'.
I32 bit;
if (exponent == 0)
- return value;
+ return value;
if (value == 0)
- return (NV)0;
+ return (NV)0;
/* On OpenVMS VAX we by default use the D_FLOAT double format,
* and that format does not have *easy* capabilities [1] for
#if ((defined(VMS) && !defined(_IEEE_FP)) || defined(_UNICOS) || defined(DOUBLE_IS_VAX_FLOAT)) && defined(NV_MAX_10_EXP)
STMT_START {
- const NV exp_v = log10(value);
- if (exponent >= NV_MAX_10_EXP || exponent + exp_v >= NV_MAX_10_EXP)
- return NV_MAX;
- if (exponent < 0) {
- if (-(exponent + exp_v) >= NV_MAX_10_EXP)
- return 0.0;
- while (-exponent >= NV_MAX_10_EXP) {
- /* combination does not overflow, but 10^(-exponent) does */
- value /= 10;
- ++exponent;
- }
- }
+ const NV exp_v = log10(value);
+ if (exponent >= NV_MAX_10_EXP || exponent + exp_v >= NV_MAX_10_EXP)
+ return NV_MAX;
+ if (exponent < 0) {
+ if (-(exponent + exp_v) >= NV_MAX_10_EXP)
+ return 0.0;
+ while (-exponent >= NV_MAX_10_EXP) {
+ /* combination does not overflow, but 10^(-exponent) does */
+ value /= 10;
+ ++exponent;
+ }
+ }
} STMT_END;
#endif
if (exponent < 0) {
- negative = 1;
- exponent = -exponent;
+ negative = 1;
+ exponent = -exponent;
#ifdef NV_MAX_10_EXP
/* for something like 1234 x 10^-309, the action of calculating
* the intermediate value 10^309 then returning 1234 / (10^309)
# define FP_OVERFLOWS_TO_ZERO
#endif
for (bit = 1; exponent; bit <<= 1) {
- if (exponent & bit) {
- exponent ^= bit;
- result *= power;
+ if (exponent & bit) {
+ exponent ^= bit;
+ result *= power;
#ifdef FP_OVERFLOWS_TO_ZERO
if (result == 0)
# ifdef NV_INF
return value < 0 ? -FLT_MAX : FLT_MAX;
# endif
#endif
- /* Floating point exceptions are supposed to be turned off,
- * but if we're obviously done, don't risk another iteration.
- */
- if (exponent == 0) break;
- }
- power *= power;
+ /* Floating point exceptions are supposed to be turned off,
+ * but if we're obviously done, don't risk another iteration.
+ */
+ if (exponent == 0) break;
+ }
+ power *= power;
}
return negative ? value / result : value * result;
}
NV
Perl_my_atof(pTHX_ const char* s)
{
- /* 's' must be NUL terminated */
+
+/*
+=for apidoc my_atof
+
+L<C<atof>(3)>, but properly works with Perl locale handling, accepting a dot
+radix character always, but also the current locale's radix character if and
+only if called from within the lexical scope of a Perl C<use locale> statement.
+
+N.B. C<s> must be NUL terminated.
+
+=cut
+*/
NV x = 0.0;
const char *p0 = negative ? s - 1 : s;
const char *p = p0;
const int infnan = grok_infnan(&p, send);
+ /* We act like PERL_SCAN_TRAILING here to permit trailing garbage,
+ * it is not clear if that is desirable.
+ */
if (infnan && p != p0) {
/* If we can generate inf/nan directly, let's do so. */
#ifdef NV_INF
const char* send = s + ((len != 0)
? len
: strlen(orig)); /* one past the last */
- bool negative = 0;
#endif
#if defined(USE_PERL_ATOF) && !defined(Perl_strtod)
+ bool negative = 0;
UV accumulator[2] = {0,0}; /* before/after dp */
bool seen_digit = 0;
I32 exp_adjust[2] = {0,0};
/* leading whitespace */
while (s < send && isSPACE(*s))
- ++s;
+ ++s;
+
+# if defined(NV_INF) || defined(NV_NAN)
+ {
+ char* endp;
+ if ((endp = S_my_atof_infnan(aTHX_ s, FALSE, send, value)))
+ return endp;
+ }
+# endif
/* sign */
switch (*s) {
- case '-':
- negative = 1;
- /* FALLTHROUGH */
- case '+':
- ++s;
+ case '-':
+# if !defined(Perl_strtod)
+ negative = 1;
+# endif
+ /* FALLTHROUGH */
+ case '+':
+ ++s;
}
#endif
char* endp;
char* copy = NULL;
- if ((endp = S_my_atof_infnan(aTHX_ s, negative, send, value)))
- return endp;
-
/* strtold() accepts 0x-prefixed hex and in POSIX implementations,
0b-prefixed binary numbers, which is backward incompatible
*/
return (char *)s+1;
}
+ /* We do not want strtod to parse whitespace after the sign, since
+ * that would give backward-incompatible results. So we rewind and
+ * let strtod handle the whitespace and sign character itself. */
+ s = orig;
+
/* If the length is passed in, the input string isn't NUL-terminated,
* and in it turns out the function below assumes it is; therefore we
* create a copy and NUL-terminate that */
Newx(copy, len + 1, char);
Copy(orig, copy, len, char);
copy[len] = '\0';
- s = copy + (s - orig);
+ s = copy;
}
result[2] = S_strtod(aTHX_ s, &endp);
}
if (s != endp) {
- *value = negative ? -result[2] : result[2];
+ /* Note that negation is handled by strtod. */
+ *value = result[2];
return endp;
}
return NULL;
* both the first and last digit, since neither can hold all values from
* 0..9; but for calculating the value we must examine those two digits.
*/
-#ifdef MAX_SIG_DIG_PLUS
+# ifdef MAX_SIG_DIG_PLUS
/* It is not necessarily the case that adding 2 to NV_DIG gets all the
possible digits in a NV, especially if NVs are not IEEE compliant
(e.g., long doubles on IRIX) - Allen <allens@cpan.org> */
-# define MAX_SIG_DIGITS (NV_DIG+MAX_SIG_DIG_PLUS)
-#else
-# define MAX_SIG_DIGITS (NV_DIG+2)
-#endif
+# define MAX_SIG_DIGITS (NV_DIG+MAX_SIG_DIG_PLUS)
+# else
+# define MAX_SIG_DIGITS (NV_DIG+2)
+# endif
/* the max number we can accumulate in a UV, and still safely do 10*N+9 */
-#define MAX_ACCUMULATE ( (UV) ((UV_MAX - 9)/10))
-
-#if defined(NV_INF) || defined(NV_NAN)
- {
- char* endp;
- if ((endp = S_my_atof_infnan(aTHX_ s, negative, send, value)))
- return endp;
- }
-#endif
+# define MAX_ACCUMULATE ( (UV) ((UV_MAX - 9)/10))
/* we accumulate digits into an integer; when this becomes too
* large, we add the total to NV and start again */
while (s < send) {
- if (isDIGIT(*s)) {
- seen_digit = 1;
- old_digit = digit;
- digit = *s++ - '0';
- if (seen_dp)
- exp_adjust[1]++;
-
- /* don't start counting until we see the first significant
- * digit, eg the 5 in 0.00005... */
- if (!sig_digits && digit == 0)
- continue;
-
- if (++sig_digits > MAX_SIG_DIGITS) {
- /* limits of precision reached */
- if (digit > 5) {
- ++accumulator[seen_dp];
- } else if (digit == 5) {
- if (old_digit % 2) { /* round to even - Allen */
- ++accumulator[seen_dp];
- }
- }
- if (seen_dp) {
- exp_adjust[1]--;
- } else {
- exp_adjust[0]++;
- }
- /* skip remaining digits */
- while (s < send && isDIGIT(*s)) {
- ++s;
- if (! seen_dp) {
- exp_adjust[0]++;
- }
- }
- /* warn of loss of precision? */
- }
- else {
- if (accumulator[seen_dp] > MAX_ACCUMULATE) {
- /* add accumulator to result and start again */
- result[seen_dp] = S_mulexp10(result[seen_dp],
- exp_acc[seen_dp])
- + (NV)accumulator[seen_dp];
- accumulator[seen_dp] = 0;
- exp_acc[seen_dp] = 0;
- }
- accumulator[seen_dp] = accumulator[seen_dp] * 10 + digit;
- ++exp_acc[seen_dp];
- }
- }
- else if (!seen_dp && GROK_NUMERIC_RADIX(&s, send)) {
- seen_dp = 1;
- if (sig_digits > MAX_SIG_DIGITS) {
- while (s < send && isDIGIT(*s)) {
- ++s;
- }
- break;
- }
- }
- else {
- break;
- }
+ if (isDIGIT(*s)) {
+ seen_digit = 1;
+ old_digit = digit;
+ digit = *s++ - '0';
+ if (seen_dp)
+ exp_adjust[1]++;
+
+ /* don't start counting until we see the first significant
+ * digit, eg the 5 in 0.00005... */
+ if (!sig_digits && digit == 0)
+ continue;
+
+ if (++sig_digits > MAX_SIG_DIGITS) {
+ /* limits of precision reached */
+ if (digit > 5) {
+ ++accumulator[seen_dp];
+ } else if (digit == 5) {
+ if (old_digit % 2) { /* round to even - Allen */
+ ++accumulator[seen_dp];
+ }
+ }
+ if (seen_dp) {
+ exp_adjust[1]--;
+ } else {
+ exp_adjust[0]++;
+ }
+ /* skip remaining digits */
+ while (s < send && isDIGIT(*s)) {
+ ++s;
+ if (! seen_dp) {
+ exp_adjust[0]++;
+ }
+ }
+ /* warn of loss of precision? */
+ }
+ else {
+ if (accumulator[seen_dp] > MAX_ACCUMULATE) {
+ /* add accumulator to result and start again */
+ result[seen_dp] = S_mulexp10(result[seen_dp],
+ exp_acc[seen_dp])
+ + (NV)accumulator[seen_dp];
+ accumulator[seen_dp] = 0;
+ exp_acc[seen_dp] = 0;
+ }
+ accumulator[seen_dp] = accumulator[seen_dp] * 10 + digit;
+ ++exp_acc[seen_dp];
+ }
+ }
+ else if (!seen_dp && GROK_NUMERIC_RADIX(&s, send)) {
+ seen_dp = 1;
+ if (sig_digits > MAX_SIG_DIGITS) {
+ while (s < send && isDIGIT(*s)) {
+ ++s;
+ }
+ break;
+ }
+ }
+ else {
+ break;
+ }
}
result[0] = S_mulexp10(result[0], exp_acc[0]) + (NV)accumulator[0];
if (seen_dp) {
- result[1] = S_mulexp10(result[1], exp_acc[1]) + (NV)accumulator[1];
+ result[1] = S_mulexp10(result[1], exp_acc[1]) + (NV)accumulator[1];
}
if (s < send && seen_digit && (isALPHA_FOLD_EQ(*s, 'e'))) {
- bool expnegative = 0;
-
- ++s;
- switch (*s) {
- case '-':
- expnegative = 1;
- /* FALLTHROUGH */
- case '+':
- ++s;
- }
- while (s < send && isDIGIT(*s))
- exponent = exponent * 10 + (*s++ - '0');
- if (expnegative)
- exponent = -exponent;
+ bool expnegative = 0;
+
+ ++s;
+ switch (*s) {
+ case '-':
+ expnegative = 1;
+ /* FALLTHROUGH */
+ case '+':
+ ++s;
+ }
+ while (s < send && isDIGIT(*s))
+ exponent = exponent * 10 + (*s++ - '0');
+ if (expnegative)
+ exponent = -exponent;
}
/* now apply the exponent */
if (seen_dp) {
- result[2] = S_mulexp10(result[0],exponent+exp_adjust[0])
- + S_mulexp10(result[1],exponent-exp_adjust[1]);
+ result[2] = S_mulexp10(result[0],exponent+exp_adjust[0])
+ + S_mulexp10(result[1],exponent-exp_adjust[1]);
} else {
- result[2] = S_mulexp10(result[0],exponent+exp_adjust[0]);
+ result[2] = S_mulexp10(result[0],exponent+exp_adjust[0]);
}
/* now apply the sign */
if (negative)
- result[2] = -result[2];
-#endif /* USE_PERL_ATOF */
+ result[2] = -result[2];
*value = result[2];
return (char *)s;
+#else /* USE_PERL_ATOF */
+ /* If you see this error you both don't have strtod (or configured -Ud_strtod or
+ or it's long double/quadmath equivalent) and disabled USE_PERL_ATOF, thus
+ removing any way for perl to convert strings to floating point numbers.
+ */
+# error No mechanism to convert strings to numbers available
+#endif
}
/*
as a number, but is careful not to trigger non-numeric or uninitialized
warnings. it assumes the caller has done C<SvGETMAGIC(sv)> already.
+Note that this always accepts trailing garbage (similar to C<grok_number_flags>
+with C<PERL_SCAN_TRAILING>), so C<"inferior"> and C<"NAND gates"> will
+return true.
+
=cut
*/