This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add 2007 copyrights in a few more .pl files that
[perl5.git] / numeric.c
index 6232f8e..6720726 100644 (file)
--- a/numeric.c
+++ b/numeric.c
@@ -1,7 +1,7 @@
 /*    numeric.c
  *
  *    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
 
 /*
 =head1 Numeric functions
+
+This file contains all the stuff needed by perl for manipulating numeric
+values, including such things as replacements for the OS's atof() function
+
+=cut
+
 */
 
 #include "EXTERN.h"
@@ -24,6 +30,7 @@
 U32
 Perl_cast_ulong(pTHX_ NV f)
 {
+    PERL_UNUSED_CONTEXT;
   if (f < 0.0)
     return f < I32_MIN ? (U32) I32_MIN : (U32)(I32) f;
   if (f < U32_MAX_P1) {
@@ -42,6 +49,7 @@ Perl_cast_ulong(pTHX_ NV f)
 I32
 Perl_cast_i32(pTHX_ NV f)
 {
+    PERL_UNUSED_CONTEXT;
   if (f < I32_MAX_P1)
     return f < I32_MIN ? I32_MIN : (I32) f;
   if (f < U32_MAX_P1) {
@@ -60,6 +68,7 @@ Perl_cast_i32(pTHX_ NV f)
 IV
 Perl_cast_iv(pTHX_ NV f)
 {
+    PERL_UNUSED_CONTEXT;
   if (f < IV_MAX_P1)
     return f < IV_MIN ? IV_MIN : (IV) f;
   if (f < UV_MAX_P1) {
@@ -79,6 +88,7 @@ Perl_cast_iv(pTHX_ NV f)
 UV
 Perl_cast_uv(pTHX_ NV f)
 {
+    PERL_UNUSED_CONTEXT;
   if (f < 0.0)
     return f < IV_MIN ? (UV) IV_MIN : (UV)(IV) f;
   if (f < UV_MAX_P1) {
@@ -94,22 +104,6 @@ Perl_cast_uv(pTHX_ NV f)
   return f > 0 ? UV_MAX : 0 /* NaN */;
 }
 
-#if defined(HUGE_VAL) || (defined(USE_LONG_DOUBLE) && defined(HUGE_VALL))
-/*
- * This hack is to force load of "huge" support from libm.a
- * So it is in perl for (say) POSIX to use.
- * Needed for SunOS with Sun's 'acc' for example.
- */
-NV
-Perl_huge(void)
-{
-#   if defined(USE_LONG_DOUBLE) && defined(HUGE_VALL)
-    return HUGE_VALL;
-#   endif
-    return HUGE_VAL;
-}
-#endif
-
 /*
 =for apidoc grok_bin
 
@@ -118,16 +112,18 @@ converts a string representing a binary number to numeric form.
 On entry I<start> and I<*len> give the string to scan, I<*flags> gives
 conversion flags, and I<result> should be NULL or a pointer to an NV.
 The scan stops at the end of the string, or the first invalid character.
-On return I<*len> is set to the length scanned string, and I<*flags> gives
-output flags.
+Unless C<PERL_SCAN_SILENT_ILLDIGIT> is set in I<*flags>, encountering an
+invalid character will also trigger a warning.
+On return I<*len> is set to the length of the scanned string,
+and I<*flags> gives output flags.
 
-If the value is <= UV_MAX it is returned as a UV, the output flags are clear,
+If the value is <= C<UV_MAX> it is returned as a UV, the output flags are clear,
 and nothing is written to I<*result>. If the value is > UV_MAX C<grok_bin>
 returns UV_MAX, sets C<PERL_SCAN_GREATER_THAN_UV_MAX> in the output flags,
 and writes the value to I<*result> (or the value is discarded if I<result>
 is NULL).
 
-The hex number may optionally be prefixed with "0b" or "b" unless
+The binary number may optionally be prefixed with "0b" or "b" unless
 C<PERL_SCAN_DISALLOW_PREFIX> is set in I<*flags> on entry. If
 C<PERL_SCAN_ALLOW_UNDERSCORES> is set in I<*flags> then the binary
 number may use '_' characters to separate digits.
@@ -136,15 +132,16 @@ number may use '_' characters to separate digits.
  */
 
 UV
-Perl_grok_bin(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
+Perl_grok_bin(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) {
     const char *s = start;
     STRLEN len = *len_p;
     UV value = 0;
     NV value_nv = 0;
 
     const UV max_div_2 = UV_MAX / 2;
-    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+    const bool allow_underscores = (bool)(*flags & PERL_SCAN_ALLOW_UNDERSCORES);
     bool overflowed = FALSE;
+    char bit;
 
     if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
         /* strip off leading b or 0b.
@@ -162,8 +159,7 @@ Perl_grok_bin(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
         }
     }
 
-    for (; len-- && *s; s++) {
-        char bit = *s;
+    for (; len-- && (bit = *s); s++) {
         if (bit == '0' || bit == '1') {
             /* Write it in this wonky order with a goto to attempt to get the
                compiler to make the common case integer-only loop pretty tight.
@@ -231,9 +227,11 @@ converts a string representing a hex number to numeric form.
 
 On entry I<start> and I<*len> give the string to scan, I<*flags> gives
 conversion flags, and I<result> should be NULL or a pointer to an NV.
-The scan stops at the end of the string, or the first non-hex-digit character.
-On return I<*len> is set to the length scanned string, and I<*flags> gives
-output flags.
+The scan stops at the end of the string, or the first invalid character.
+Unless C<PERL_SCAN_SILENT_ILLDIGIT> is set in I<*flags>, encountering an
+invalid character will also trigger a warning.
+On return I<*len> is set to the length of the scanned string,
+and I<*flags> gives output flags.
 
 If the value is <= UV_MAX it is returned as a UV, the output flags are clear,
 and nothing is written to I<*result>. If the value is > UV_MAX C<grok_hex>
@@ -250,16 +248,16 @@ number may use '_' characters to separate digits.
  */
 
 UV
-Perl_grok_hex(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
+Perl_grok_hex(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) {
+    dVAR;
     const char *s = start;
     STRLEN len = *len_p;
     UV value = 0;
     NV value_nv = 0;
 
     const UV max_div_16 = UV_MAX / 16;
-    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+    const bool allow_underscores = (bool)(*flags & PERL_SCAN_ALLOW_UNDERSCORES);
     bool overflowed = FALSE;
-    const char *hexdigit;
 
     if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
         /* strip off leading x or 0x.
@@ -278,7 +276,7 @@ Perl_grok_hex(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
     }
 
     for (; len-- && *s; s++) {
-       hexdigit = strchr((char *) PL_hexdigit, *s);
+       const char *hexdigit = strchr(PL_hexdigit, *s);
         if (hexdigit) {
             /* Write it in this wonky order with a goto to attempt to get the
                compiler to make the common case integer-only loop pretty tight.
@@ -307,7 +305,7 @@ Perl_grok_hex(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
             continue;
         }
         if (*s == '_' && len && allow_underscores && s[1]
-               && (hexdigit = strchr((char *) PL_hexdigit, s[1])))
+               && (hexdigit = strchr(PL_hexdigit, s[1])))
            {
                --len;
                ++s;
@@ -342,19 +340,37 @@ Perl_grok_hex(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
 /*
 =for apidoc grok_oct
 
+converts a string representing an octal number to numeric form.
+
+On entry I<start> and I<*len> give the string to scan, I<*flags> gives
+conversion flags, and I<result> should be NULL or a pointer to an NV.
+The scan stops at the end of the string, or the first invalid character.
+Unless C<PERL_SCAN_SILENT_ILLDIGIT> is set in I<*flags>, encountering an
+invalid character will also trigger a warning.
+On return I<*len> is set to the length of the scanned string,
+and I<*flags> gives output flags.
+
+If the value is <= UV_MAX it is returned as a UV, the output flags are clear,
+and nothing is written to I<*result>. If the value is > UV_MAX C<grok_oct>
+returns UV_MAX, sets C<PERL_SCAN_GREATER_THAN_UV_MAX> in the output flags,
+and writes the value to I<*result> (or the value is discarded if I<result>
+is NULL).
+
+If C<PERL_SCAN_ALLOW_UNDERSCORES> is set in I<*flags> then the octal
+number may use '_' characters to separate digits.
 
 =cut
  */
 
 UV
-Perl_grok_oct(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
+Perl_grok_oct(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) {
     const char *s = start;
     STRLEN len = *len_p;
     UV value = 0;
     NV value_nv = 0;
 
     const UV max_div_8 = UV_MAX / 8;
-    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+    const bool allow_underscores = (bool)(*flags & PERL_SCAN_ALLOW_UNDERSCORES);
     bool overflowed = FALSE;
 
     for (; len-- && *s; s++) {
@@ -396,7 +412,7 @@ Perl_grok_oct(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result) {
                 goto redo;
            }
         /* Allow \octal to work the DWIM way (that is, stop scanning
-         * as soon as non-octal characters are seen, complain only iff
+         * as soon as non-octal characters are seen, complain only if
          * someone seems to want to use the digits eight and nine). */
         if (digit == 8 || digit == 9) {
             if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT) && ckWARN(WARN_DIGIT))
@@ -443,33 +459,33 @@ For backwards compatibility. Use C<grok_oct> instead.
  */
 
 NV
-Perl_scan_bin(pTHX_ char *start, STRLEN len, STRLEN *retlen)
+Perl_scan_bin(pTHX_ const char *start, STRLEN len, STRLEN *retlen)
 {
     NV rnv;
     I32 flags = *retlen ? PERL_SCAN_ALLOW_UNDERSCORES : 0;
-    UV ruv = grok_bin (start, &len, &flags, &rnv);
+    const UV ruv = grok_bin (start, &len, &flags, &rnv);
 
     *retlen = len;
     return (flags & PERL_SCAN_GREATER_THAN_UV_MAX) ? rnv : (NV)ruv;
 }
 
 NV
-Perl_scan_oct(pTHX_ char *start, STRLEN len, STRLEN *retlen)
+Perl_scan_oct(pTHX_ const char *start, STRLEN len, STRLEN *retlen)
 {
     NV rnv;
     I32 flags = *retlen ? PERL_SCAN_ALLOW_UNDERSCORES : 0;
-    UV ruv = grok_oct (start, &len, &flags, &rnv);
+    const UV ruv = grok_oct (start, &len, &flags, &rnv);
 
     *retlen = len;
     return (flags & PERL_SCAN_GREATER_THAN_UV_MAX) ? rnv : (NV)ruv;
 }
 
 NV
-Perl_scan_hex(pTHX_ char *start, STRLEN len, STRLEN *retlen)
+Perl_scan_hex(pTHX_ const char *start, STRLEN len, STRLEN *retlen)
 {
     NV rnv;
     I32 flags = *retlen ? PERL_SCAN_ALLOW_UNDERSCORES : 0;
-    UV ruv = grok_hex (start, &len, &flags, &rnv);
+    const UV ruv = grok_hex (start, &len, &flags, &rnv);
 
     *retlen = len;
     return (flags & PERL_SCAN_GREATER_THAN_UV_MAX) ? rnv : (NV)ruv;
@@ -486,9 +502,10 @@ bool
 Perl_grok_numeric_radix(pTHX_ const char **sp, const char *send)
 {
 #ifdef USE_LOCALE_NUMERIC
+    dVAR;
     if (PL_numeric_radix_sv && IN_LOCALE) { 
         STRLEN len;
-        char* radix = SvPV(PL_numeric_radix_sv, len);
+        const char * const radix = SvPV(PL_numeric_radix_sv, len);
         if (*sp + len <= send && memEQ(*sp, radix, len)) {
             *sp += len;
             return TRUE; 
@@ -531,7 +548,7 @@ int
 Perl_grok_number(pTHX_ const char *pv, STRLEN len, UV *valuep)
 {
   const char *s = pv;
-  const char *send = pv + len;
+  const char * const send = pv + len;
   const UV max_div_10 = UV_MAX / 10;
   const char max_mod_10 = UV_MAX % 10;
   int numtype = 0;
@@ -729,7 +746,7 @@ S_mulexp10(NV value, I32 exponent)
     if (exponent == 0)
        return value;
     if (value == 0)
-       return 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
@@ -753,7 +770,7 @@ S_mulexp10(NV value, I32 exponent)
 
 #if ((defined(VMS) && !defined(__IEEE_FP)) || defined(_UNICOS)) && defined(NV_MAX_10_EXP)
     STMT_START {
-       NV exp_v = log10(value);
+       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) {
@@ -791,6 +808,7 @@ Perl_my_atof(pTHX_ const char* s)
 {
     NV x = 0.0;
 #ifdef USE_LOCALE_NUMERIC
+    dVAR;
     if (PL_numeric_local && IN_LOCALE) {
        NV y;
 
@@ -815,11 +833,11 @@ char*
 Perl_my_atof2(pTHX_ const char* orig, NV* value)
 {
     NV result[3] = {0.0, 0.0, 0.0};
-    char* s = (char*)orig;
+    const char* s = orig;
 #ifdef USE_PERL_ATOF
     UV accumulator[2] = {0,0}; /* before/after dp */
     bool negative = 0;
-    char* send = s + strlen(orig) - 1;
+    const char* send = s + strlen(orig) - 1;
     bool seen_digit = 0;
     I32 exp_adjust[2] = {0,0};
     I32 exp_acc[2] = {-1, -1};
@@ -865,6 +883,21 @@ Perl_my_atof2(pTHX_ const char* orig, NV* value)
            ++s;
     }
 
+    /* punt to strtod for NaN/Inf; if no support for it there, tough luck */
+
+#ifdef HAS_STRTOD
+    if (*s == 'n' || *s == 'N' || *s == 'i' || *s == 'I') {
+        const char *p = negative ? s - 1 : s;
+        char *endp;
+        NV rslt;
+        rslt = strtod(p, &endp);
+        if (endp != p) {
+            *value = rslt;
+            return (char *)endp;
+        }
+    }
+#endif
+
     /* we accumulate digits into an integer; when this becomes too
      * large, we add the total to NV and start again */
 
@@ -917,7 +950,7 @@ Perl_my_atof2(pTHX_ const char* orig, NV* value)
                ++exp_acc[seen_dp];
            }
        }
-       else if (!seen_dp && GROK_NUMERIC_RADIX((const char **)&s, send)) {
+       else if (!seen_dp && GROK_NUMERIC_RADIX(&s, send)) {
            seen_dp = 1;
            if (sig_digits > MAX_SIG_DIGITS) {
                ++s;
@@ -970,7 +1003,7 @@ Perl_my_atof2(pTHX_ const char* orig, NV* value)
        result[2] = -result[2];
 #endif /* USE_PERL_ATOF */
     *value = result[2];
-    return s;
+    return (char *)s;
 }
 
 #if ! defined(HAS_MODFL) && defined(HAS_AINTL) && defined(HAS_COPYSIGNL)
@@ -989,3 +1022,13 @@ Perl_my_frexpl(long double x, int *e) {
        return (scalbnl(x, -*e));
 }
 #endif
+
+/*
+ * Local variables:
+ * c-indentation-style: bsd
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set ts=8 sts=4 sw=4 noet:
+ */