]> git.saurik.com Git - apple/libc.git/blobdiff - gdtoa/gdtoa-strtod-fbsd.c
Libc-583.tar.gz
[apple/libc.git] / gdtoa / gdtoa-strtod-fbsd.c
index bf9b093db58b1a662232d86bedba87976adebaa9..538b0665b18128f33c11878b3e0233c8b1eb0eca 100644 (file)
@@ -44,16 +44,15 @@ THIS SOFTWARE.
 #ifndef NO_IEEE_Scale
 #define Avoid_Underflow
 #undef tinytens
-/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* The factor of 2^106 in tinytens[4] helps us avoid setting the underflow */
 /* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
 static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
-               9007199254740992.e-256
+               9007199254740992.*9007199254740992.e-256
                };
 #endif
 #endif
 
 #ifdef Honor_FLT_ROUNDS
-#define Rounding rounding
 #undef Check_FLT_ROUNDS
 #define Check_FLT_ROUNDS
 #else
@@ -81,13 +80,36 @@ strtod_l
 #ifdef SET_INEXACT
        int inexact, oldinexact;
 #endif
-#ifdef Honor_FLT_ROUNDS
-       int rounding = Flt_Rounds;
-#endif
 #ifdef USE_LOCALE
-       char *decimal_point;
-       int decimal_point_len;
-#endif /* USE_LOCALE */
+       NORMALIZE_LOCALE(loc);
+#ifdef NO_LOCALE_CACHE
+       char *decimalpoint = localeconv_l(loc)->decimal_point;
+#else
+       char *decimalpoint;
+       static char *decimalpoint_cache;
+       if (!(s0 = decimalpoint_cache)) {
+               s0 = localeconv_l(loc)->decimal_point;
+               if ((decimalpoint_cache = (char*)malloc(strlen(s0) + 1))) {
+                       strcpy(decimalpoint_cache, s0);
+                       s0 = decimalpoint_cache;
+                       }
+               }
+       decimalpoint = (char*)s0;
+#endif
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+       int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+       Rounding = Flt_Rounds;
+#else /*}{*/
+       Rounding = 1;
+       switch(fegetround()) {
+         case FE_TOWARDZERO:   Rounding = 0; break;
+         case FE_UPWARD:       Rounding = 2; break;
+         case FE_DOWNWARD:     Rounding = 3;
+         }
+#endif /*}}*/
+#endif /*}*/
 
        sign = nz0 = nz = decpt = 0;
        dval(rv) = 0.;
@@ -113,7 +135,7 @@ strtod_l
                }
  break2:
        if (*s == '0') {
-#ifndef NO_HEX_FP
+#ifndef NO_HEX_FP /*{*/
                {
                static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI };
                Long exp;
@@ -122,16 +144,20 @@ strtod_l
                  case 'x':
                  case 'X':
                        {
-#if defined(FE_DOWNWARD) && defined(FE_TONEAREST) && defined(FE_TOWARDZERO) && defined(FE_UPWARD)
+#if defined(FE_DOWNWARD) && defined(FE_TONEAREST) && defined(FE_TOWARDZERO) && defined(FE_UPWARD) /*{{*/
                        FPI fpi1 = fpi;
+#ifdef Honor_FLT_ROUNDS /*{{*/
+                       fpi1.rounding = Rounding;
+#else /*}{*/
                        switch(fegetround()) {
                          case FE_TOWARDZERO:   fpi1.rounding = 0; break;
                          case FE_UPWARD:       fpi1.rounding = 2; break;
                          case FE_DOWNWARD:     fpi1.rounding = 3;
                          }
-#else
+#endif /*}}*/
+#else /*}{*/
 #define fpi1 fpi
-#endif
+#endif /*}}*/
                        switch((i = gethex(&s, &fpi1, &exp, &bb, sign, loc)) & STRTOG_Retmask) {
                          case STRTOG_NoNumber:
                                s = s00;
@@ -148,7 +174,7 @@ strtod_l
                        goto ret;
                  }
                }
-#endif
+#endif /*}*/
                nz0 = 1;
                while(*++s == '0') ;
                if (!*s)
@@ -162,22 +188,18 @@ strtod_l
                else if (nd < 16)
                        z = 10*z + c - '0';
        nd0 = nd;
-       NORMALIZE_LOCALE(loc);
 #ifdef USE_LOCALE
-       decimal_point = localeconv_l(loc)->decimal_point;
-       decimal_point_len = strlen(decimal_point);
-       if (strncmp(s, decimal_point, decimal_point_len) == 0)
-#else
-       if (c == '.')
-#endif
-               {
-               decpt = 1;
-#ifdef USE_LOCALE
-               s += decimal_point_len;
+       if (c == *decimalpoint) {
+               for(i = 1; decimalpoint[i]; ++i)
+                       if (s[i] != decimalpoint[i])
+                               goto dig_done;
+               s += i;
                c = *s;
 #else
+       if (c == '.') {
                c = *++s;
 #endif
+               decpt = 1;
                if (!nd) {
                        for(; c == '0'; c = *++s)
                                nz++;
@@ -206,7 +228,7 @@ strtod_l
                                nz = 0;
                                }
                        }
-               }
+               }/*}*/
  dig_done:
        e = 0;
        if (c == 'e' || c == 'E') {
@@ -393,12 +415,12 @@ strtod_l
        scale = 0;
 #endif
 #ifdef Honor_FLT_ROUNDS
-       if (rounding >= 2) {
+       if (Rounding >= 2) {
                if (sign)
-                       rounding = rounding == 2 ? 0 : 2;
+                       Rounding = Rounding == 2 ? 0 : 2;
                else
-                       if (rounding != 2)
-                               rounding = 0;
+                       if (Rounding != 2)
+                               Rounding = 0;
                }
 #endif
 #endif /*IEEE_Arith*/
@@ -417,7 +439,7 @@ strtod_l
                                /* Can't trust HUGE_VAL */
 #ifdef IEEE_Arith
 #ifdef Honor_FLT_ROUNDS
-                               switch(rounding) {
+                               switch(Rounding) {
                                  case 0: /* toward 0 */
                                  case 3: /* toward -infinity */
                                        word0(rv) = Big0;
@@ -527,7 +549,7 @@ strtod_l
        /* Put digits into bd: true value = bd * 10^e */
 
 #ifdef USE_LOCALE
-       bd0 = s2b(s0, nd0, nd, y, decimal_point_len);
+       bd0 = s2b(s0, nd0, nd, y, strlen(decimalpoint));
 #else
        bd0 = s2b(s0, nd0, nd, y, 1);
 #endif
@@ -552,7 +574,7 @@ strtod_l
                        bd2 -= bbe;
                bs2 = bb2;
 #ifdef Honor_FLT_ROUNDS
-               if (rounding != 1)
+               if (Rounding != 1)
                        bs2++;
 #endif
 #ifdef Avoid_Underflow
@@ -610,7 +632,7 @@ strtod_l
                delta->sign = 0;
                i = cmp(delta, bs);
 #ifdef Honor_FLT_ROUNDS
-               if (rounding != 1) {
+               if (Rounding != 1) {
                        if (i < 0) {
                                /* Error is less than an ulp */
                                if (!delta->x[0] && delta->wds <= 1) {
@@ -620,7 +642,7 @@ strtod_l
 #endif
                                        break;
                                        }
-                               if (rounding) {
+                               if (Rounding) {
                                        if (dsign) {
                                                adj = 1.;
                                                goto apply_adj;
@@ -666,10 +688,10 @@ strtod_l
                        if (adj < 1.)
                                adj = 1.;
                        if (adj <= 0x7ffffffe) {
-                               /* adj = rounding ? ceil(adj) : floor(adj); */
+                               /* adj = Rounding ? ceil(adj) : floor(adj); */
                                y = adj;
                                if (y != adj) {
-                                       if (!((rounding>>1) ^ dsign))
+                                       if (!((Rounding>>1) ^ dsign))
                                                y++;
                                        adj = y;
                                        }
@@ -692,8 +714,11 @@ strtod_l
 #endif /*Sudden_Underflow*/
 #endif /*Avoid_Underflow*/
                        adj *= ulp(dval(rv));
-                       if (dsign)
+                       if (dsign) {
+                               if (word0(rv) == Big0 && word1(rv) == Big1)
+                                       goto ovfl;
                                dval(rv) += adj;
+                               }
                        else
                                dval(rv) -= adj;
                        goto cont;
@@ -786,7 +811,7 @@ strtod_l
                                        }
 #endif /*Avoid_Underflow*/
                                L = (word0(rv) & Exp_mask) - Exp_msk1;
-#endif /*Sudden_Underflow}*/
+#endif /*Sudden_Underflow}}*/
                                word0(rv) = L | Bndry_mask1;
                                word1(rv) = 0xffffffff;
 #ifdef IBM
@@ -974,11 +999,11 @@ strtod_l
                dval(rv) *= dval(rv0);
 #ifndef NO_ERRNO
                /* try to avoid the bug of testing an 8087 register value */
-#if __DARWIN_UNIX03
-               if (word0(rv) == 0 && word1(rv) == 0 || dval(rv) < DBL_MIN)
-#else /* !__DARWIN_UNIX03 */
+#if defined(IEEE_Arith) && __DARWIN_UNIX03
+               if (!(word0(rv) & Exp_mask))
+#else
                if (word0(rv) == 0 && word1(rv) == 0)
-#endif /* __DARWIN_UNIX03 */
+#endif
                        errno = ERANGE;
 #endif
                }