The logic of choosing strtol/strtoul/strtoll/strtoull was wrong
Jarkko Hietaniemi [Thu, 4 May 2000 15:26:37 +0000 (15:26 +0000)]
in natively 64-bit platforms where a long is a quad (no need
for long longs).  Also added bias for IVs.

p4raw-id: //depot/cfgperl@6059

toke.c

diff --git a/toke.c b/toke.c
index 10273a0..49a1193 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -6705,7 +6705,7 @@ Perl_scan_num(pTHX_ char *start)
     register char *s = start;          /* current position in buffer */
     register char *d;                  /* destination in temp buffer */
     register char *e;                  /* end of temp buffer */
-    NV value;                          /* number read, as a double */
+    NV nv;                             /* number read, as a double */
     SV *sv = Nullsv;                   /* place to put the converted number */
     bool floatit;                      /* boolean: int or float? */
     char *lastub = 0;                  /* position of last underbar */
@@ -6962,40 +6962,9 @@ Perl_scan_num(pTHX_ char *start)
        /* make an sv from the string */
        sv = NEWSV(92,0);
 
-       /* unfortunately this monster needs to be on one line or
-          makedepend will be confused. */
-#if (defined(USE_64_BIT_INT) && (!defined(HAS_STRTOLL)|| !defined(HAS_STRTOULL))) || (!defined(USE_64_BIT_INT) && (!defined(HAS_STRTOL) || !defined(HAS_STRTOUL)))
+#if defined(Strtol) && defined(Strtoul)
 
        /*
-          No working strto[u]l[l]. Since atoi() doesn't do range checks,
-          we need to do this the hard way.
-        */
-
-       value = Atof(PL_tokenbuf);
-
-       /* 
-          See if we can make do with an integer value without loss of
-          precision.  We use I_V to cast to an int, because some
-          compilers have issues.  Then we try casting it back and see
-          if it was the same.  We only do this if we know we
-          specifically read an integer.
-
-          Note: if floatit is true, then we don't need to do the
-          conversion at all.
-       */
-       {
-           UV tryuv = U_V(value);
-           if (!floatit && (NV)tryuv == value) {
-               if (tryuv <= IV_MAX)
-                   sv_setiv(sv, (IV)tryuv);
-               else
-                   sv_setuv(sv, tryuv);
-           }
-           else
-               sv_setnv(sv, value);
-       }
-#else
-       /*
           strtol/strtoll sets errno to ERANGE if the number is too big
           for an integer. We try to do an integer conversion first
           if no characters indicating "float" have been found.
@@ -7010,15 +6979,62 @@ Perl_scan_num(pTHX_ char *start)
            else
                uv = Strtoul(PL_tokenbuf, (char**)NULL, 10);
            if (errno)
-               floatit = TRUE; /* probably just too large */
+               floatit = TRUE; /* Probably just too large. */
            else if (*PL_tokenbuf == '-')
                sv_setiv(sv, iv);
+           else if (uv <= IV_MAX)
+               sv_setiv(sv, uv); /* Prefer IVs over UVs. */
            else
                sv_setuv(sv, uv);
        }
        if (floatit) {
-           value = Atof(PL_tokenbuf);
-           sv_setnv(sv, value);
+           nv = Atof(PL_tokenbuf);
+           sv_setnv(sv, nv);
+       }
+#else
+       /*
+          No working strtou?ll?.
+
+          Unfortunately atol() doesn't do range checks (returning
+          LONG_MIN/LONG_MAX, and setting errno to ERANGE on overflows)
+          everywhere [1], so we cannot use use atol() (or atoll()).
+          If we could, they would be used, as Atol(), very much like
+          Strtol() and Strtoul() are used above.
+
+          [1] XXX Configure test needed to check for atol()
+                  (and atoll() overflow behaviour) XXX --jhi
+
+          We need to do this the hard way.  */
+
+       nv = Atof(PL_tokenbuf);
+
+       /* See if we can make do with an integer value without loss of
+          precision.  We use U_V to cast to a UV, because some
+          compilers have issues.  Then we try casting it back and see
+          if it was the same [1].  We only do this if we know we
+          specifically read an integer.  If floatit is true, then we
+          don't need to do the conversion at all. 
+
+          [1] Note that this is lossy if our NVs cannot preserve our
+          UVs.  There is a metaconfig define, NV_PRESERVES_UV, but we
+          really do hope all such platforms have strtou?ll? to do a
+          lossless IV/UV conversion.
+          XXX Configure test needed to check how many UV bits
+              do our NVs preserve, really (the current test checks
+              for the roundtrip of ~0) XXX --jhi
+              Maybe do some tricks with DBL_MANT_DIG and LDBL_MANT_DIG,
+              and DBL_DIG, LDBL_DIG (this is already available as NV_DIG)?
+          */
+       {
+           UV uv = U_V(nv);
+           if (!floatit && (NV)uv == nv) {
+               if (uv <= IV_MAX)
+                   sv_setiv(sv, uv); /* Prefer IVs over UVs. */
+               else
+                   sv_setuv(sv, uv);
+           }
+           else
+               sv_setnv(sv, nv);
        }
 #endif
        if ( floatit ? (PL_hints & HINT_NEW_FLOAT) :