]> git.saurik.com Git - apple/libc.git/blobdiff - gdtoa/FreeBSD/gdtoa-strtod.c
Libc-763.11.tar.gz
[apple/libc.git] / gdtoa / FreeBSD / gdtoa-strtod.c
index 4913d5089c946a2fb75b7c28ef097844432dcf8d..fdc933a1ef98d73c304bf5b16c194d7720272d6c 100644 (file)
@@ -26,12 +26,13 @@ THIS SOFTWARE.
 
 ****************************************************************/
 
-/* Please send bug reports to
-       David M. Gay
-       dmg@acm.org
- */
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").     */
 
 #include "gdtoaimp.h"
+#ifndef NO_FENV_H
+#include <fenv.h>
+#endif
 
 #ifdef USE_LOCALE
 #include "locale.h"
@@ -41,16 +42,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
@@ -68,22 +68,55 @@ strtod
 #ifdef Avoid_Underflow
        int scale;
 #endif
-       int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+       int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, dsign,
                 e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
        CONST char *s, *s0, *s1;
-       double aadj, aadj1, adj, rv, rv0;
+       double aadj;
        Long L;
+       U adj, aadj1, rv, rv0;
        ULong y, z;
        Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
 #ifdef SET_INEXACT
        int inexact, oldinexact;
 #endif
-#ifdef Honor_FLT_ROUNDS
-       int rounding;
-#endif
+#ifdef USE_LOCALE /*{{*/
+#ifdef NO_LOCALE_CACHE
+       char *decimalpoint = localeconv()->decimal_point;
+       int dplen = strlen(decimalpoint);
+#else
+       char *decimalpoint;
+       static char *decimalpoint_cache;
+       static int dplen;
+       if (!(s0 = decimalpoint_cache)) {
+               s0 = localeconv()->decimal_point;
+               if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
+                       strcpy(decimalpoint_cache, s0);
+                       s0 = decimalpoint_cache;
+                       }
+               dplen = strlen(s0);
+               }
+       decimalpoint = (char*)s0;
+#endif /*NO_LOCALE_CACHE*/
+#else  /*USE_LOCALE}{*/
+#define dplen 1
+#endif /*USE_LOCALE}}*/
+
+#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 = 0;
-       dval(rv) = 0.;
+       sign = nz0 = nz = decpt = 0;
+       dval(&rv) = 0.;
        for(s = s00;;s++) switch(*s) {
                case '-':
                        sign = 1;
@@ -106,7 +139,7 @@ strtod
                }
  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;
@@ -114,7 +147,14 @@ strtod
                switch(s[1]) {
                  case 'x':
                  case 'X':
-                       switch((i = gethex(&s, &fpi, &exp, &bb, sign)) & STRTOG_Retmask) {
+                       {
+#ifdef Honor_FLT_ROUNDS
+                       FPI fpi1 = fpi;
+                       fpi1.rounding = Rounding;
+#else
+#define fpi1 fpi
+#endif
+                       switch((i = gethex(&s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) {
                          case STRTOG_NoNumber:
                                s = s00;
                                sign = 0;
@@ -126,11 +166,11 @@ strtod
                                        Bfree(bb);
                                        }
                                ULtod(((U*)&rv)->L, bits, exp, i);
-                         }
+                         }}
                        goto ret;
                  }
                }
-#endif
+#endif /*}*/
                nz0 = 1;
                while(*++s == '0') ;
                if (!*s)
@@ -145,12 +185,17 @@ strtod
                        z = 10*z + c - '0';
        nd0 = nd;
 #ifdef USE_LOCALE
-       if (c == *localeconv()->decimal_point)
+       if (c == *decimalpoint) {
+               for(i = 1; decimalpoint[i]; ++i)
+                       if (s[i] != decimalpoint[i])
+                               goto dig_done;
+               s += i;
+               c = *s;
 #else
-       if (c == '.')
-#endif
-               {
+       if (c == '.') {
                c = *++s;
+#endif
+               decpt = 1;
                if (!nd) {
                        for(; c == '0'; c = *++s)
                                nz++;
@@ -179,7 +224,7 @@ strtod
                                nz = 0;
                                }
                        }
-               }
+               }/*}*/
  dig_done:
        e = 0;
        if (c == 'e' || c == 'E') {
@@ -225,15 +270,16 @@ strtod
                        ULong bits[2];
                        static FPI fpinan =     /* only 52 explicit bits */
                                { 52, 1-1023-53+1, 2046-1023-53+1, 1, SI };
-                       switch(c) {
+                       if (!decpt)
+                        switch(c) {
                          case 'i':
                          case 'I':
                                if (match(&s,"nf")) {
                                        --s;
                                        if (!match(&s,"inity"))
                                                ++s;
-                                       word0(rv) = 0x7ff00000;
-                                       word1(rv) = 0;
+                                       word0(&rv) = 0x7ff00000;
+                                       word1(&rv) = 0;
                                        goto ret;
                                        }
                                break;
@@ -244,12 +290,14 @@ strtod
                                        if (*s == '(' /*)*/
                                         && hexnan(&s, &fpinan, bits)
                                                        == STRTOG_NaNbits) {
-                                               word0(rv) = 0x7ff00000 | bits[1];
-                                               word1(rv) = bits[0];
+                                               word0(&rv) = 0x7ff00000 | bits[1];
+                                               word1(&rv) = bits[0];
                                                }
                                        else {
-                                               word0(rv) = NAN_WORD0;
-                                               word1(rv) = NAN_WORD1;
+#endif
+                                               word0(&rv) = NAN_WORD0;
+                                               word1(&rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
                                                }
 #endif
                                        goto ret;
@@ -272,13 +320,13 @@ strtod
        if (!nd0)
                nd0 = nd;
        k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
-       dval(rv) = y;
+       dval(&rv) = y;
        if (k > 9) {
 #ifdef SET_INEXACT
                if (k > DBL_DIG)
                        oldinexact = get_inexact();
 #endif
-               dval(rv) = tens[k - 9] * dval(rv) + z;
+               dval(&rv) = tens[k - 9] * dval(&rv) + z;
                }
        bd0 = 0;
        if (nd <= DBL_DIG
@@ -302,7 +350,7 @@ strtod
                                        sign = 0;
                                        }
 #endif
-                               /* rv = */ rounded_product(dval(rv), tens[e]);
+                               /* rv = */ rounded_product(dval(&rv), tens[e]);
                                goto ret;
 #endif
                                }
@@ -319,20 +367,20 @@ strtod
                                        }
 #endif
                                e -= i;
-                               dval(rv) *= tens[i];
+                               dval(&rv) *= tens[i];
 #ifdef VAX
                                /* VAX exponent range is so narrow we must
                                 * worry about overflow here...
                                 */
  vax_ovfl_check:
-                               word0(rv) -= P*Exp_msk1;
-                               /* rv = */ rounded_product(dval(rv), tens[e]);
-                               if ((word0(rv) & Exp_mask)
+                               word0(&rv) -= P*Exp_msk1;
+                               /* rv = */ rounded_product(dval(&rv), tens[e]);
+                               if ((word0(&rv) & Exp_mask)
                                 > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
                                        goto ovfl;
-                               word0(rv) += P*Exp_msk1;
+                               word0(&rv) += P*Exp_msk1;
 #else
-                               /* rv = */ rounded_product(dval(rv), tens[e]);
+                               /* rv = */ rounded_product(dval(&rv), tens[e]);
 #endif
                                goto ret;
                                }
@@ -346,7 +394,7 @@ strtod
                                sign = 0;
                                }
 #endif
-                       /* rv = */ rounded_quotient(dval(rv), tens[-e]);
+                       /* rv = */ rounded_quotient(dval(&rv), tens[-e]);
                        goto ret;
                        }
 #endif
@@ -363,12 +411,12 @@ strtod
        scale = 0;
 #endif
 #ifdef Honor_FLT_ROUNDS
-       if ((rounding = Flt_Rounds) >= 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*/
@@ -377,7 +425,7 @@ strtod
 
        if (e1 > 0) {
                if ( (i = e1 & 15) !=0)
-                       dval(rv) *= tens[i];
+                       dval(&rv) *= tens[i];
                if (e1 &= ~15) {
                        if (e1 > DBL_MAX_10_EXP) {
  ovfl:
@@ -387,28 +435,28 @@ strtod
                                /* 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;
-                                       word1(rv) = Big1;
+                                       word0(&rv) = Big0;
+                                       word1(&rv) = Big1;
                                        break;
                                  default:
-                                       word0(rv) = Exp_mask;
-                                       word1(rv) = 0;
+                                       word0(&rv) = Exp_mask;
+                                       word1(&rv) = 0;
                                  }
 #else /*Honor_FLT_ROUNDS*/
-                               word0(rv) = Exp_mask;
-                               word1(rv) = 0;
+                               word0(&rv) = Exp_mask;
+                               word1(&rv) = 0;
 #endif /*Honor_FLT_ROUNDS*/
 #ifdef SET_INEXACT
                                /* set overflow bit */
-                               dval(rv0) = 1e300;
-                               dval(rv0) *= dval(rv0);
+                               dval(&rv0) = 1e300;
+                               dval(&rv0) *= dval(&rv0);
 #endif
 #else /*IEEE_Arith*/
-                               word0(rv) = Big0;
-                               word1(rv) = Big1;
+                               word0(&rv) = Big0;
+                               word1(&rv) = Big1;
 #endif /*IEEE_Arith*/
                                if (bd0)
                                        goto retfree;
@@ -417,27 +465,27 @@ strtod
                        e1 >>= 4;
                        for(j = 0; e1 > 1; j++, e1 >>= 1)
                                if (e1 & 1)
-                                       dval(rv) *= bigtens[j];
+                                       dval(&rv) *= bigtens[j];
                /* The last multiplication could overflow. */
-                       word0(rv) -= P*Exp_msk1;
-                       dval(rv) *= bigtens[j];
-                       if ((z = word0(rv) & Exp_mask)
+                       word0(&rv) -= P*Exp_msk1;
+                       dval(&rv) *= bigtens[j];
+                       if ((z = word0(&rv) & Exp_mask)
                         > Exp_msk1*(DBL_MAX_EXP+Bias-P))
                                goto ovfl;
                        if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
                                /* set to largest number */
                                /* (Can't trust DBL_MAX) */
-                               word0(rv) = Big0;
-                               word1(rv) = Big1;
+                               word0(&rv) = Big0;
+                               word1(&rv) = Big1;
                                }
                        else
-                               word0(rv) += P*Exp_msk1;
+                               word0(&rv) += P*Exp_msk1;
                        }
                }
        else if (e1 < 0) {
                e1 = -e1;
                if ( (i = e1 & 15) !=0)
-                       dval(rv) /= tens[i];
+                       dval(&rv) /= tens[i];
                if (e1 >>= 4) {
                        if (e1 >= 1 << n_bigtens)
                                goto undfl;
@@ -446,34 +494,34 @@ strtod
                                scale = 2*P;
                        for(j = 0; e1 > 0; j++, e1 >>= 1)
                                if (e1 & 1)
-                                       dval(rv) *= tinytens[j];
-                       if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask)
+                                       dval(&rv) *= tinytens[j];
+                       if (scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask)
                                                >> Exp_shift)) > 0) {
                                /* scaled rv is denormal; zap j low bits */
                                if (j >= 32) {
-                                       word1(rv) = 0;
+                                       word1(&rv) = 0;
                                        if (j >= 53)
-                                        word0(rv) = (P+2)*Exp_msk1;
+                                        word0(&rv) = (P+2)*Exp_msk1;
                                        else
-                                        word0(rv) &= 0xffffffff << j-32;
+                                        word0(&rv) &= 0xffffffff << (j-32);
                                        }
                                else
-                                       word1(rv) &= 0xffffffff << j;
+                                       word1(&rv) &= 0xffffffff << j;
                                }
 #else
                        for(j = 0; e1 > 1; j++, e1 >>= 1)
                                if (e1 & 1)
-                                       dval(rv) *= tinytens[j];
+                                       dval(&rv) *= tinytens[j];
                        /* The last multiplication could underflow. */
-                       dval(rv0) = dval(rv);
-                       dval(rv) *= tinytens[j];
-                       if (!dval(rv)) {
-                               dval(rv) = 2.*dval(rv0);
-                               dval(rv) *= tinytens[j];
+                       dval(&rv0) = dval(&rv);
+                       dval(&rv) *= tinytens[j];
+                       if (!dval(&rv)) {
+                               dval(&rv) = 2.*dval(&rv0);
+                               dval(&rv) *= tinytens[j];
 #endif
-                               if (!dval(rv)) {
+                               if (!dval(&rv)) {
  undfl:
-                                       dval(rv) = 0.;
+                                       dval(&rv) = 0.;
 #ifndef NO_ERRNO
                                        errno = ERANGE;
 #endif
@@ -482,8 +530,8 @@ strtod
                                        goto ret;
                                        }
 #ifndef Avoid_Underflow
-                               word0(rv) = Tiny0;
-                               word1(rv) = Tiny1;
+                               word0(&rv) = Tiny0;
+                               word1(&rv) = Tiny1;
                                /* The refinement below will clean
                                 * this approximation up.
                                 */
@@ -496,12 +544,12 @@ strtod
 
        /* Put digits into bd: true value = bd * 10^e */
 
-       bd0 = s2b(s0, nd0, nd, y);
+       bd0 = s2b(s0, nd0, nd, y, dplen);
 
        for(;;) {
                bd = Balloc(bd0->k);
                Bcopy(bd, bd0);
-               bb = d2b(dval(rv), &bbe, &bbbits);      /* rv = bb * 2^bbe */
+               bb = d2b(dval(&rv), &bbe, &bbbits);     /* rv = bb * 2^bbe */
                bs = i2b(1);
 
                if (e >= 0) {
@@ -518,12 +566,12 @@ strtod
                        bd2 -= bbe;
                bs2 = bb2;
 #ifdef Honor_FLT_ROUNDS
-               if (rounding != 1)
+               if (Rounding != 1)
                        bs2++;
 #endif
 #ifdef Avoid_Underflow
                j = bbe - scale;
-               i = j + bbbits - 1;     /* logb(rv) */
+               i = j + bbbits - 1;     /* logb(&rv) */
                if (i < Emin)   /* denormal */
                        j += P - Emin;
                else
@@ -537,7 +585,7 @@ strtod
 #endif
 #else /*Sudden_Underflow*/
                j = bbe;
-               i = j + bbbits - 1;     /* logb(rv) */
+               i = j + bbbits - 1;     /* logb(&rv) */
                if (i < Emin)   /* denormal */
                        j += P - Emin;
                else
@@ -576,7 +624,7 @@ strtod
                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) {
@@ -586,17 +634,17 @@ strtod
 #endif
                                        break;
                                        }
-                               if (rounding) {
+                               if (Rounding) {
                                        if (dsign) {
-                                               adj = 1.;
+                                               dval(&adj) = 1.;
                                                goto apply_adj;
                                                }
                                        }
                                else if (!dsign) {
-                                       adj = -1.;
-                                       if (!word1(rv)
-                                        && !(word0(rv) & Frac_mask)) {
-                                               y = word0(rv) & Exp_mask;
+                                       dval(&adj) = -1.;
+                                       if (!word1(&rv)
+                                        && !(word0(&rv) & Frac_mask)) {
+                                               y = word0(&rv) & Exp_mask;
 #ifdef Avoid_Underflow
                                                if (!scale || y > 2*P*Exp_msk1)
 #else
@@ -605,63 +653,66 @@ strtod
                                                  {
                                                  delta = lshift(delta,Log2P);
                                                  if (cmp(delta, bs) <= 0)
-                                                       adj = -0.5;
+                                                       dval(&adj) = -0.5;
                                                  }
                                                }
  apply_adj:
 #ifdef Avoid_Underflow
-                                       if (scale && (y = word0(rv) & Exp_mask)
+                                       if (scale && (y = word0(&rv) & Exp_mask)
                                                <= 2*P*Exp_msk1)
-                                         word0(adj) += (2*P+1)*Exp_msk1 - y;
+                                         word0(&adj) += (2*P+1)*Exp_msk1 - y;
 #else
 #ifdef Sudden_Underflow
-                                       if ((word0(rv) & Exp_mask) <=
+                                       if ((word0(&rv) & Exp_mask) <=
                                                        P*Exp_msk1) {
-                                               word0(rv) += P*Exp_msk1;
-                                               dval(rv) += adj*ulp(dval(rv));
-                                               word0(rv) -= P*Exp_msk1;
+                                               word0(&rv) += P*Exp_msk1;
+                                               dval(&rv) += adj*ulp(&rv);
+                                               word0(&rv) -= P*Exp_msk1;
                                                }
                                        else
 #endif /*Sudden_Underflow*/
 #endif /*Avoid_Underflow*/
-                                       dval(rv) += adj*ulp(dval(rv));
+                                       dval(&rv) += adj*ulp(&rv);
                                        }
                                break;
                                }
-                       adj = ratio(delta, bs);
+                       dval(&adj) = ratio(delta, bs);
                        if (adj < 1.)
-                               adj = 1.;
+                               dval(&adj) = 1.;
                        if (adj <= 0x7ffffffe) {
-                               /* adj = rounding ? ceil(adj) : floor(adj); */
+                               /* dval(&adj) = Rounding ? ceil(&adj) : floor(&adj); */
                                y = adj;
                                if (y != adj) {
-                                       if (!((rounding>>1) ^ dsign))
+                                       if (!((Rounding>>1) ^ dsign))
                                                y++;
-                                       adj = y;
+                                       dval(&adj) = y;
                                        }
                                }
 #ifdef Avoid_Underflow
-                       if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
-                               word0(adj) += (2*P+1)*Exp_msk1 - y;
+                       if (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
+                               word0(&adj) += (2*P+1)*Exp_msk1 - y;
 #else
 #ifdef Sudden_Underflow
-                       if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
-                               word0(rv) += P*Exp_msk1;
-                               adj *= ulp(dval(rv));
+                       if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+                               word0(&rv) += P*Exp_msk1;
+                               dval(&adj) *= ulp(&rv);
                                if (dsign)
-                                       dval(rv) += adj;
+                                       dval(&rv) += adj;
                                else
-                                       dval(rv) -= adj;
-                               word0(rv) -= P*Exp_msk1;
+                                       dval(&rv) -= adj;
+                               word0(&rv) -= P*Exp_msk1;
                                goto cont;
                                }
 #endif /*Sudden_Underflow*/
 #endif /*Avoid_Underflow*/
-                       adj *= ulp(dval(rv));
-                       if (dsign)
-                               dval(rv) += adj;
+                       dval(&adj) *= ulp(&rv);
+                       if (dsign) {
+                               if (word0(&rv) == Big0 && word1(&rv) == Big1)
+                                       goto ovfl;
+                               dval(&rv) += adj;
+                               }
                        else
-                               dval(rv) -= adj;
+                               dval(&rv) -= adj;
                        goto cont;
                        }
 #endif /*Honor_FLT_ROUNDS*/
@@ -670,12 +721,12 @@ strtod
                        /* Error is less than half an ulp -- check for
                         * special case of mantissa a power of two.
                         */
-                       if (dsign || word1(rv) || word0(rv) & Bndry_mask
+                       if (dsign || word1(&rv) || word0(&rv) & Bndry_mask
 #ifdef IEEE_Arith
 #ifdef Avoid_Underflow
-                        || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+                        || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1
 #else
-                        || (word0(rv) & Exp_mask) <= Exp_msk1
+                        || (word0(&rv) & Exp_mask) <= Exp_msk1
 #endif
 #endif
                                ) {
@@ -700,32 +751,32 @@ strtod
                if (i == 0) {
                        /* exactly half-way between */
                        if (dsign) {
-                               if ((word0(rv) & Bndry_mask1) == Bndry_mask1
-                                &&  word1(rv) == (
+                               if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
+                                &&  word1(&rv) == (
 #ifdef Avoid_Underflow
-                       (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+                       (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
                ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
 #endif
                                                   0xffffffff)) {
                                        /*boundary case -- increment exponent*/
-                                       word0(rv) = (word0(rv) & Exp_mask)
+                                       word0(&rv) = (word0(&rv) & Exp_mask)
                                                + Exp_msk1
 #ifdef IBM
                                                | Exp_msk1 >> 4
 #endif
                                                ;
-                                       word1(rv) = 0;
+                                       word1(&rv) = 0;
 #ifdef Avoid_Underflow
                                        dsign = 0;
 #endif
                                        break;
                                        }
                                }
-                       else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+                       else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
  drop_down:
                                /* boundary case -- decrement exponent */
 #ifdef Sudden_Underflow /*{{*/
-                               L = word0(rv) & Exp_mask;
+                               L = word0(&rv) & Exp_mask;
 #ifdef IBM
                                if (L <  Exp_msk1)
 #else
@@ -740,7 +791,7 @@ strtod
 #else /*Sudden_Underflow}{*/
 #ifdef Avoid_Underflow
                                if (scale) {
-                                       L = word0(rv) & Exp_mask;
+                                       L = word0(&rv) & Exp_mask;
                                        if (L <= (2*P+1)*Exp_msk1) {
                                                if (L > (P+2)*Exp_msk1)
                                                        /* round even ==> */
@@ -751,10 +802,10 @@ strtod
                                                }
                                        }
 #endif /*Avoid_Underflow*/
-                               L = (word0(rv) & Exp_mask) - Exp_msk1;
-#endif /*Sudden_Underflow}*/
-                               word0(rv) = L | Bndry_mask1;
-                               word1(rv) = 0xffffffff;
+                               L = (word0(&rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+                               word0(&rv) = L | Bndry_mask1;
+                               word1(&rv) = 0xffffffff;
 #ifdef IBM
                                goto cont;
 #else
@@ -762,16 +813,16 @@ strtod
 #endif
                                }
 #ifndef ROUND_BIASED
-                       if (!(word1(rv) & LSB))
+                       if (!(word1(&rv) & LSB))
                                break;
 #endif
                        if (dsign)
-                               dval(rv) += ulp(dval(rv));
+                               dval(&rv) += ulp(&rv);
 #ifndef ROUND_BIASED
                        else {
-                               dval(rv) -= ulp(dval(rv));
+                               dval(&rv) -= ulp(&rv);
 #ifndef Sudden_Underflow
-                               if (!dval(rv))
+                               if (!dval(&rv))
                                        goto undfl;
 #endif
                                }
@@ -783,14 +834,14 @@ strtod
                        }
                if ((aadj = ratio(delta, bs)) <= 2.) {
                        if (dsign)
-                               aadj = aadj1 = 1.;
-                       else if (word1(rv) || word0(rv) & Bndry_mask) {
+                               aadj = dval(&aadj1) = 1.;
+                       else if (word1(&rv) || word0(&rv) & Bndry_mask) {
 #ifndef Sudden_Underflow
-                               if (word1(rv) == Tiny1 && !word0(rv))
+                               if (word1(&rv) == Tiny1 && !word0(&rv))
                                        goto undfl;
 #endif
                                aadj = 1.;
-                               aadj1 = -1.;
+                               dval(&aadj1) = -1.;
                                }
                        else {
                                /* special case -- power of FLT_RADIX to be */
@@ -800,45 +851,45 @@ strtod
                                        aadj = 1./FLT_RADIX;
                                else
                                        aadj *= 0.5;
-                               aadj1 = -aadj;
+                               dval(&aadj1) = -aadj;
                                }
                        }
                else {
                        aadj *= 0.5;
-                       aadj1 = dsign ? aadj : -aadj;
+                       dval(&aadj1) = dsign ? aadj : -aadj;
 #ifdef Check_FLT_ROUNDS
                        switch(Rounding) {
                                case 2: /* towards +infinity */
-                                       aadj1 -= 0.5;
+                                       dval(&aadj1) -= 0.5;
                                        break;
                                case 0: /* towards 0 */
                                case 3: /* towards -infinity */
-                                       aadj1 += 0.5;
+                                       dval(&aadj1) += 0.5;
                                }
 #else
                        if (Flt_Rounds == 0)
-                               aadj1 += 0.5;
+                               dval(&aadj1) += 0.5;
 #endif /*Check_FLT_ROUNDS*/
                        }
-               y = word0(rv) & Exp_mask;
+               y = word0(&rv) & Exp_mask;
 
                /* Check for overflow */
 
                if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
-                       dval(rv0) = dval(rv);
-                       word0(rv) -= P*Exp_msk1;
-                       adj = aadj1 * ulp(dval(rv));
-                       dval(rv) += adj;
-                       if ((word0(rv) & Exp_mask) >=
+                       dval(&rv0) = dval(&rv);
+                       word0(&rv) -= P*Exp_msk1;
+                       dval(&adj) = dval(&aadj1) * ulp(&rv);
+                       dval(&rv) += dval(&adj);
+                       if ((word0(&rv) & Exp_mask) >=
                                        Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
-                               if (word0(rv0) == Big0 && word1(rv0) == Big1)
+                               if (word0(&rv0) == Big0 && word1(&rv0) == Big1)
                                        goto ovfl;
-                               word0(rv) = Big0;
-                               word1(rv) = Big1;
+                               word0(&rv) = Big0;
+                               word1(&rv) = Big1;
                                goto cont;
                                }
                        else
-                               word0(rv) += P*Exp_msk1;
+                               word0(&rv) += P*Exp_msk1;
                        }
                else {
 #ifdef Avoid_Underflow
@@ -847,58 +898,58 @@ strtod
                                        if ((z = aadj) <= 0)
                                                z = 1;
                                        aadj = z;
-                                       aadj1 = dsign ? aadj : -aadj;
+                                       dval(&aadj1) = dsign ? aadj : -aadj;
                                        }
-                               word0(aadj1) += (2*P+1)*Exp_msk1 - y;
+                               word0(&aadj1) += (2*P+1)*Exp_msk1 - y;
                                }
-                       adj = aadj1 * ulp(dval(rv));
-                       dval(rv) += adj;
+                       dval(&adj) = dval(&aadj1) * ulp(&rv);
+                       dval(&rv) += dval(&adj);
 #else
 #ifdef Sudden_Underflow
-                       if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
-                               dval(rv0) = dval(rv);
-                               word0(rv) += P*Exp_msk1;
-                               adj = aadj1 * ulp(dval(rv));
-                               dval(rv) += adj;
+                       if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+                               dval(&rv0) = dval(&rv);
+                               word0(&rv) += P*Exp_msk1;
+                               dval(&adj) = dval(&aadj1) * ulp(&rv);
+                               dval(&rv) += adj;
 #ifdef IBM
-                               if ((word0(rv) & Exp_mask) <  P*Exp_msk1)
+                               if ((word0(&rv) & Exp_mask) <  P*Exp_msk1)
 #else
-                               if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+                               if ((word0(&rv) & Exp_mask) <= P*Exp_msk1)
 #endif
                                        {
-                                       if (word0(rv0) == Tiny0
-                                        && word1(rv0) == Tiny1)
+                                       if (word0(&rv0) == Tiny0
+                                        && word1(&rv0) == Tiny1)
                                                goto undfl;
-                                       word0(rv) = Tiny0;
-                                       word1(rv) = Tiny1;
+                                       word0(&rv) = Tiny0;
+                                       word1(&rv) = Tiny1;
                                        goto cont;
                                        }
                                else
-                                       word0(rv) -= P*Exp_msk1;
+                                       word0(&rv) -= P*Exp_msk1;
                                }
                        else {
-                               adj = aadj1 * ulp(dval(rv));
-                               dval(rv) += adj;
+                               dval(&adj) = dval(&aadj1) * ulp(&rv);
+                               dval(&rv) += adj;
                                }
 #else /*Sudden_Underflow*/
-                       /* Compute adj so that the IEEE rounding rules will
-                        * correctly round rv + adj in some half-way cases.
-                        * If rv * ulp(rv) is denormalized (i.e.,
+                       /* Compute dval(&adj) so that the IEEE rounding rules will
+                        * correctly round rv + dval(&adj) in some half-way cases.
+                        * If rv * ulp(&rv) is denormalized (i.e.,
                         * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
                         * trouble from bits lost to denormalization;
                         * example: 1.2e-307 .
                         */
                        if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
-                               aadj1 = (double)(int)(aadj + 0.5);
+                               dval(&aadj1) = (double)(int)(aadj + 0.5);
                                if (!dsign)
-                                       aadj1 = -aadj1;
+                                       dval(&aadj1) = -dval(&aadj1);
                                }
-                       adj = aadj1 * ulp(dval(rv));
-                       dval(rv) += adj;
+                       dval(&adj) = dval(&aadj1) * ulp(&rv);
+                       dval(&rv) += adj;
 #endif /*Sudden_Underflow*/
 #endif /*Avoid_Underflow*/
                        }
-               z = word0(rv) & Exp_mask;
+               z = word0(&rv) & Exp_mask;
 #ifndef SET_INEXACT
 #ifdef Avoid_Underflow
                if (!scale)
@@ -908,7 +959,7 @@ strtod
                        L = (Long)aadj;
                        aadj -= L;
                        /* The tolerances below are conservative. */
-                       if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+                       if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
                                if (aadj < .4999999 || aadj > .5000001)
                                        break;
                                }
@@ -925,9 +976,9 @@ strtod
 #ifdef SET_INEXACT
        if (inexact) {
                if (!oldinexact) {
-                       word0(rv0) = Exp_1 + (70 << Exp_shift);
-                       word1(rv0) = 0;
-                       dval(rv0) += 1.;
+                       word0(&rv0) = Exp_1 + (70 << Exp_shift);
+                       word1(&rv0) = 0;
+                       dval(&rv0) += 1.;
                        }
                }
        else if (!oldinexact)
@@ -935,21 +986,25 @@ strtod
 #endif
 #ifdef Avoid_Underflow
        if (scale) {
-               word0(rv0) = Exp_1 - 2*P*Exp_msk1;
-               word1(rv0) = 0;
-               dval(rv) *= dval(rv0);
+               word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
+               word1(&rv0) = 0;
+               dval(&rv) *= dval(&rv0);
 #ifndef NO_ERRNO
                /* try to avoid the bug of testing an 8087 register value */
-               if (word0(rv) == 0 && word1(rv) == 0)
+#ifdef IEEE_Arith
+               if (!(word0(&rv) & Exp_mask))
+#else
+               if (word0(&rv) == 0 && word1(&rv) == 0)
+#endif
                        errno = ERANGE;
 #endif
                }
 #endif /* Avoid_Underflow */
 #ifdef SET_INEXACT
-       if (inexact && !(word0(rv) & Exp_mask)) {
+       if (inexact && !(word0(&rv) & Exp_mask)) {
                /* set underflow bit */
-               dval(rv0) = 1e-300;
-               dval(rv0) *= dval(rv0);
+               dval(&rv0) = 1e-300;
+               dval(&rv0) *= dval(&rv0);
                }
 #endif
  retfree:
@@ -961,6 +1016,6 @@ strtod
  ret:
        if (se)
                *se = (char *)s;
-       return sign ? -dval(rv) : dval(rv);
+       return sign ? -dval(&rv) : dval(&rv);
        }