1112158Sdas/**************************************************************** 2112158Sdas 3112158SdasThe author of this software is David M. Gay. 4112158Sdas 5112158SdasCopyright (C) 1998-2001 by Lucent Technologies 6112158SdasAll Rights Reserved 7112158Sdas 8112158SdasPermission to use, copy, modify, and distribute this software and 9112158Sdasits documentation for any purpose and without fee is hereby 10112158Sdasgranted, provided that the above copyright notice appear in all 11112158Sdascopies and that both that the copyright notice and this 12112158Sdaspermission notice and warranty disclaimer appear in supporting 13112158Sdasdocumentation, and that the name of Lucent or any of its entities 14112158Sdasnot be used in advertising or publicity pertaining to 15112158Sdasdistribution of the software without specific, written prior 16112158Sdaspermission. 17112158Sdas 18112158SdasLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19112158SdasINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 20112158SdasIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 21112158SdasSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22112158SdasWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 23112158SdasIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 24112158SdasARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 25112158SdasTHIS SOFTWARE. 26112158Sdas 27112158Sdas****************************************************************/ 28112158Sdas 29165743Sdas/* Please send bug reports to David M. Gay (dmg at acm dot org, 30165743Sdas * with " at " changed at "@" and " dot " changed to "."). */ 31112158Sdas 32174679Sdas/* $FreeBSD$ */ 33174679Sdas 34112158Sdas#include "gdtoaimp.h" 35165743Sdas#ifndef NO_FENV_H 36165743Sdas#include <fenv.h> 37165743Sdas#endif 38112158Sdas 39112158Sdas#ifdef USE_LOCALE 40112158Sdas#include "locale.h" 41112158Sdas#endif 42112158Sdas 43112158Sdas#ifdef IEEE_Arith 44112158Sdas#ifndef NO_IEEE_Scale 45112158Sdas#define Avoid_Underflow 46112158Sdas#undef tinytens 47182709Sdas/* The factor of 2^106 in tinytens[4] helps us avoid setting the underflow */ 48112158Sdas/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ 49112158Sdasstatic CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 50182709Sdas 9007199254740992.*9007199254740992.e-256 51112158Sdas }; 52112158Sdas#endif 53112158Sdas#endif 54112158Sdas 55112158Sdas#ifdef Honor_FLT_ROUNDS 56112158Sdas#undef Check_FLT_ROUNDS 57112158Sdas#define Check_FLT_ROUNDS 58112158Sdas#else 59112158Sdas#define Rounding Flt_Rounds 60112158Sdas#endif 61112158Sdas 62219557Sdas#ifdef Avoid_Underflow /*{*/ 63219557Sdas static double 64219557Sdassulp 65219557Sdas#ifdef KR_headers 66219557Sdas (x, scale) U *x; int scale; 67219557Sdas#else 68219557Sdas (U *x, int scale) 69219557Sdas#endif 70219557Sdas{ 71219557Sdas U u; 72219557Sdas double rv; 73219557Sdas int i; 74219557Sdas 75219557Sdas rv = ulp(x); 76219557Sdas if (!scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) 77219557Sdas return rv; /* Is there an example where i <= 0 ? */ 78219557Sdas word0(&u) = Exp_1 + (i << Exp_shift); 79219557Sdas word1(&u) = 0; 80219557Sdas return rv * u.d; 81219557Sdas } 82219557Sdas#endif /*}*/ 83219557Sdas 84112158Sdas double 85235785Stheravenstrtod_l 86112158Sdas#ifdef KR_headers 87235785Stheraven (s00, se, loc) CONST char *s00; char **se; locale_t loc 88112158Sdas#else 89235785Stheraven (CONST char *s00, char **se, locale_t loc) 90112158Sdas#endif 91112158Sdas{ 92112158Sdas#ifdef Avoid_Underflow 93112158Sdas int scale; 94112158Sdas#endif 95165743Sdas int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, dsign, 96112158Sdas e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; 97112158Sdas CONST char *s, *s0, *s1; 98219557Sdas double aadj; 99112158Sdas Long L; 100219557Sdas U adj, aadj1, rv, rv0; 101112158Sdas ULong y, z; 102112158Sdas Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; 103219557Sdas#ifdef Avoid_Underflow 104219557Sdas ULong Lsb, Lsb1; 105219557Sdas#endif 106112158Sdas#ifdef SET_INEXACT 107112158Sdas int inexact, oldinexact; 108112158Sdas#endif 109187808Sdas#ifdef USE_LOCALE /*{{*/ 110187808Sdas#ifdef NO_LOCALE_CACHE 111235785Stheraven char *decimalpoint = localeconv_l(loc)->decimal_point; 112187808Sdas int dplen = strlen(decimalpoint); 113187808Sdas#else 114187808Sdas char *decimalpoint; 115187808Sdas static char *decimalpoint_cache; 116187808Sdas static int dplen; 117187808Sdas if (!(s0 = decimalpoint_cache)) { 118235785Stheraven s0 = localeconv_l(loc)->decimal_point; 119219557Sdas if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { 120187808Sdas strcpy(decimalpoint_cache, s0); 121187808Sdas s0 = decimalpoint_cache; 122187808Sdas } 123187808Sdas dplen = strlen(s0); 124187808Sdas } 125187808Sdas decimalpoint = (char*)s0; 126187808Sdas#endif /*NO_LOCALE_CACHE*/ 127187808Sdas#else /*USE_LOCALE}{*/ 128187808Sdas#define dplen 1 129187808Sdas#endif /*USE_LOCALE}}*/ 130187808Sdas 131182709Sdas#ifdef Honor_FLT_ROUNDS /*{*/ 132182709Sdas int Rounding; 133182709Sdas#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ 134182709Sdas Rounding = Flt_Rounds; 135182709Sdas#else /*}{*/ 136182709Sdas Rounding = 1; 137182709Sdas switch(fegetround()) { 138182709Sdas case FE_TOWARDZERO: Rounding = 0; break; 139182709Sdas case FE_UPWARD: Rounding = 2; break; 140182709Sdas case FE_DOWNWARD: Rounding = 3; 141182709Sdas } 142182709Sdas#endif /*}}*/ 143182709Sdas#endif /*}*/ 144112158Sdas 145165743Sdas sign = nz0 = nz = decpt = 0; 146219557Sdas dval(&rv) = 0.; 147112158Sdas for(s = s00;;s++) switch(*s) { 148112158Sdas case '-': 149112158Sdas sign = 1; 150112158Sdas /* no break */ 151112158Sdas case '+': 152112158Sdas if (*++s) 153112158Sdas goto break2; 154112158Sdas /* no break */ 155112158Sdas case 0: 156112158Sdas goto ret0; 157112158Sdas case '\t': 158112158Sdas case '\n': 159112158Sdas case '\v': 160112158Sdas case '\f': 161112158Sdas case '\r': 162112158Sdas case ' ': 163112158Sdas continue; 164112158Sdas default: 165112158Sdas goto break2; 166112158Sdas } 167112158Sdas break2: 168112158Sdas if (*s == '0') { 169187808Sdas#ifndef NO_HEX_FP /*{*/ 170112158Sdas { 171112158Sdas static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; 172112158Sdas Long exp; 173112158Sdas ULong bits[2]; 174112158Sdas switch(s[1]) { 175112158Sdas case 'x': 176112158Sdas case 'X': 177165743Sdas { 178219557Sdas#ifdef Honor_FLT_ROUNDS 179165743Sdas FPI fpi1 = fpi; 180182709Sdas fpi1.rounding = Rounding; 181219557Sdas#else 182165743Sdas#define fpi1 fpi 183219557Sdas#endif 184165743Sdas switch((i = gethex(&s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) { 185112158Sdas case STRTOG_NoNumber: 186112158Sdas s = s00; 187112158Sdas sign = 0; 188112158Sdas case STRTOG_Zero: 189112158Sdas break; 190112158Sdas default: 191124703Sdas if (bb) { 192124703Sdas copybits(bits, fpi.nbits, bb); 193124703Sdas Bfree(bb); 194124703Sdas } 195112158Sdas ULtod(((U*)&rv)->L, bits, exp, i); 196165743Sdas }} 197112158Sdas goto ret; 198112158Sdas } 199112158Sdas } 200187808Sdas#endif /*}*/ 201112158Sdas nz0 = 1; 202112158Sdas while(*++s == '0') ; 203112158Sdas if (!*s) 204112158Sdas goto ret; 205112158Sdas } 206112158Sdas s0 = s; 207112158Sdas y = z = 0; 208112158Sdas for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) 209112158Sdas if (nd < 9) 210112158Sdas y = 10*y + c - '0'; 211112158Sdas else if (nd < 16) 212112158Sdas z = 10*z + c - '0'; 213112158Sdas nd0 = nd; 214112158Sdas#ifdef USE_LOCALE 215187808Sdas if (c == *decimalpoint) { 216187808Sdas for(i = 1; decimalpoint[i]; ++i) 217187808Sdas if (s[i] != decimalpoint[i]) 218187808Sdas goto dig_done; 219187808Sdas s += i; 220187808Sdas c = *s; 221112415Sdas#else 222187808Sdas if (c == '.') { 223187808Sdas c = *++s; 224112158Sdas#endif 225165743Sdas decpt = 1; 226112158Sdas if (!nd) { 227112158Sdas for(; c == '0'; c = *++s) 228112158Sdas nz++; 229112158Sdas if (c > '0' && c <= '9') { 230112158Sdas s0 = s; 231112158Sdas nf += nz; 232112158Sdas nz = 0; 233112158Sdas goto have_dig; 234112158Sdas } 235112158Sdas goto dig_done; 236112158Sdas } 237112158Sdas for(; c >= '0' && c <= '9'; c = *++s) { 238112158Sdas have_dig: 239112158Sdas nz++; 240112158Sdas if (c -= '0') { 241112158Sdas nf += nz; 242112158Sdas for(i = 1; i < nz; i++) 243112158Sdas if (nd++ < 9) 244112158Sdas y *= 10; 245112158Sdas else if (nd <= DBL_DIG + 1) 246112158Sdas z *= 10; 247112158Sdas if (nd++ < 9) 248112158Sdas y = 10*y + c; 249112158Sdas else if (nd <= DBL_DIG + 1) 250112158Sdas z = 10*z + c; 251112158Sdas nz = 0; 252112158Sdas } 253112158Sdas } 254187808Sdas }/*}*/ 255112158Sdas dig_done: 256112158Sdas e = 0; 257112158Sdas if (c == 'e' || c == 'E') { 258112158Sdas if (!nd && !nz && !nz0) { 259112158Sdas goto ret0; 260112158Sdas } 261112158Sdas s00 = s; 262112158Sdas esign = 0; 263112158Sdas switch(c = *++s) { 264112158Sdas case '-': 265112158Sdas esign = 1; 266112158Sdas case '+': 267112158Sdas c = *++s; 268112158Sdas } 269112158Sdas if (c >= '0' && c <= '9') { 270112158Sdas while(c == '0') 271112158Sdas c = *++s; 272112158Sdas if (c > '0' && c <= '9') { 273112158Sdas L = c - '0'; 274112158Sdas s1 = s; 275112158Sdas while((c = *++s) >= '0' && c <= '9') 276112158Sdas L = 10*L + c - '0'; 277112158Sdas if (s - s1 > 8 || L > 19999) 278112158Sdas /* Avoid confusion from exponents 279112158Sdas * so large that e might overflow. 280112158Sdas */ 281112158Sdas e = 19999; /* safe for 16 bit ints */ 282112158Sdas else 283112158Sdas e = (int)L; 284112158Sdas if (esign) 285112158Sdas e = -e; 286112158Sdas } 287112158Sdas else 288112158Sdas e = 0; 289112158Sdas } 290112158Sdas else 291112158Sdas s = s00; 292112158Sdas } 293112158Sdas if (!nd) { 294112158Sdas if (!nz && !nz0) { 295112158Sdas#ifdef INFNAN_CHECK 296112158Sdas /* Check for Nan and Infinity */ 297112158Sdas ULong bits[2]; 298112158Sdas static FPI fpinan = /* only 52 explicit bits */ 299112158Sdas { 52, 1-1023-53+1, 2046-1023-53+1, 1, SI }; 300165743Sdas if (!decpt) 301165743Sdas switch(c) { 302112158Sdas case 'i': 303112158Sdas case 'I': 304112158Sdas if (match(&s,"nf")) { 305112158Sdas --s; 306112158Sdas if (!match(&s,"inity")) 307112158Sdas ++s; 308219557Sdas word0(&rv) = 0x7ff00000; 309219557Sdas word1(&rv) = 0; 310112158Sdas goto ret; 311112158Sdas } 312112158Sdas break; 313112158Sdas case 'n': 314112158Sdas case 'N': 315112158Sdas if (match(&s, "an")) { 316112158Sdas#ifndef No_Hex_NaN 317112158Sdas if (*s == '(' /*)*/ 318112158Sdas && hexnan(&s, &fpinan, bits) 319112158Sdas == STRTOG_NaNbits) { 320219557Sdas word0(&rv) = 0x7ff80000 | bits[1]; 321219557Sdas word1(&rv) = bits[0]; 322112158Sdas } 323112158Sdas else { 324165743Sdas#endif 325219557Sdas word0(&rv) = NAN_WORD0; 326219557Sdas word1(&rv) = NAN_WORD1; 327165743Sdas#ifndef No_Hex_NaN 328112158Sdas } 329112158Sdas#endif 330112158Sdas goto ret; 331112158Sdas } 332112158Sdas } 333112158Sdas#endif /* INFNAN_CHECK */ 334112158Sdas ret0: 335112158Sdas s = s00; 336112158Sdas sign = 0; 337112158Sdas } 338112158Sdas goto ret; 339112158Sdas } 340112158Sdas e1 = e -= nf; 341112158Sdas 342112158Sdas /* Now we have nd0 digits, starting at s0, followed by a 343112158Sdas * decimal point, followed by nd-nd0 digits. The number we're 344112158Sdas * after is the integer represented by those digits times 345112158Sdas * 10**e */ 346112158Sdas 347112158Sdas if (!nd0) 348112158Sdas nd0 = nd; 349112158Sdas k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; 350219557Sdas dval(&rv) = y; 351112158Sdas if (k > 9) { 352112158Sdas#ifdef SET_INEXACT 353112158Sdas if (k > DBL_DIG) 354112158Sdas oldinexact = get_inexact(); 355112158Sdas#endif 356219557Sdas dval(&rv) = tens[k - 9] * dval(&rv) + z; 357112158Sdas } 358112158Sdas bd0 = 0; 359112158Sdas if (nd <= DBL_DIG 360112158Sdas#ifndef RND_PRODQUOT 361112158Sdas#ifndef Honor_FLT_ROUNDS 362112158Sdas && Flt_Rounds == 1 363112158Sdas#endif 364112158Sdas#endif 365112158Sdas ) { 366112158Sdas if (!e) 367112158Sdas goto ret; 368219557Sdas#ifndef ROUND_BIASED_without_Round_Up 369112158Sdas if (e > 0) { 370112158Sdas if (e <= Ten_pmax) { 371112158Sdas#ifdef VAX 372112158Sdas goto vax_ovfl_check; 373112158Sdas#else 374112158Sdas#ifdef Honor_FLT_ROUNDS 375112158Sdas /* round correctly FLT_ROUNDS = 2 or 3 */ 376112158Sdas if (sign) { 377219557Sdas rv.d = -rv.d; 378112158Sdas sign = 0; 379112158Sdas } 380112158Sdas#endif 381219557Sdas /* rv = */ rounded_product(dval(&rv), tens[e]); 382112158Sdas goto ret; 383112158Sdas#endif 384112158Sdas } 385112158Sdas i = DBL_DIG - nd; 386112158Sdas if (e <= Ten_pmax + i) { 387112158Sdas /* A fancier test would sometimes let us do 388112158Sdas * this for larger i values. 389112158Sdas */ 390112158Sdas#ifdef Honor_FLT_ROUNDS 391112158Sdas /* round correctly FLT_ROUNDS = 2 or 3 */ 392112158Sdas if (sign) { 393219557Sdas rv.d = -rv.d; 394112158Sdas sign = 0; 395112158Sdas } 396112158Sdas#endif 397112158Sdas e -= i; 398219557Sdas dval(&rv) *= tens[i]; 399112158Sdas#ifdef VAX 400112158Sdas /* VAX exponent range is so narrow we must 401112158Sdas * worry about overflow here... 402112158Sdas */ 403112158Sdas vax_ovfl_check: 404219557Sdas word0(&rv) -= P*Exp_msk1; 405219557Sdas /* rv = */ rounded_product(dval(&rv), tens[e]); 406219557Sdas if ((word0(&rv) & Exp_mask) 407112158Sdas > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) 408112158Sdas goto ovfl; 409219557Sdas word0(&rv) += P*Exp_msk1; 410112158Sdas#else 411219557Sdas /* rv = */ rounded_product(dval(&rv), tens[e]); 412112158Sdas#endif 413112158Sdas goto ret; 414112158Sdas } 415112158Sdas } 416112158Sdas#ifndef Inaccurate_Divide 417112158Sdas else if (e >= -Ten_pmax) { 418112158Sdas#ifdef Honor_FLT_ROUNDS 419112158Sdas /* round correctly FLT_ROUNDS = 2 or 3 */ 420112158Sdas if (sign) { 421219557Sdas rv.d = -rv.d; 422112158Sdas sign = 0; 423112158Sdas } 424112158Sdas#endif 425219557Sdas /* rv = */ rounded_quotient(dval(&rv), tens[-e]); 426112158Sdas goto ret; 427112158Sdas } 428112158Sdas#endif 429219557Sdas#endif /* ROUND_BIASED_without_Round_Up */ 430112158Sdas } 431112158Sdas e1 += nd - k; 432112158Sdas 433112158Sdas#ifdef IEEE_Arith 434112158Sdas#ifdef SET_INEXACT 435112158Sdas inexact = 1; 436112158Sdas if (k <= DBL_DIG) 437112158Sdas oldinexact = get_inexact(); 438112158Sdas#endif 439112158Sdas#ifdef Avoid_Underflow 440112158Sdas scale = 0; 441112158Sdas#endif 442112158Sdas#ifdef Honor_FLT_ROUNDS 443182709Sdas if (Rounding >= 2) { 444112158Sdas if (sign) 445182709Sdas Rounding = Rounding == 2 ? 0 : 2; 446112158Sdas else 447182709Sdas if (Rounding != 2) 448182709Sdas Rounding = 0; 449112158Sdas } 450112158Sdas#endif 451112158Sdas#endif /*IEEE_Arith*/ 452112158Sdas 453112158Sdas /* Get starting approximation = rv * 10**e1 */ 454112158Sdas 455112158Sdas if (e1 > 0) { 456112158Sdas if ( (i = e1 & 15) !=0) 457219557Sdas dval(&rv) *= tens[i]; 458112158Sdas if (e1 &= ~15) { 459112158Sdas if (e1 > DBL_MAX_10_EXP) { 460112158Sdas ovfl: 461112158Sdas /* Can't trust HUGE_VAL */ 462112158Sdas#ifdef IEEE_Arith 463112158Sdas#ifdef Honor_FLT_ROUNDS 464182709Sdas switch(Rounding) { 465112158Sdas case 0: /* toward 0 */ 466112158Sdas case 3: /* toward -infinity */ 467219557Sdas word0(&rv) = Big0; 468219557Sdas word1(&rv) = Big1; 469112158Sdas break; 470112158Sdas default: 471219557Sdas word0(&rv) = Exp_mask; 472219557Sdas word1(&rv) = 0; 473112158Sdas } 474112158Sdas#else /*Honor_FLT_ROUNDS*/ 475219557Sdas word0(&rv) = Exp_mask; 476219557Sdas word1(&rv) = 0; 477112158Sdas#endif /*Honor_FLT_ROUNDS*/ 478112158Sdas#ifdef SET_INEXACT 479112158Sdas /* set overflow bit */ 480219557Sdas dval(&rv0) = 1e300; 481219557Sdas dval(&rv0) *= dval(&rv0); 482112158Sdas#endif 483112158Sdas#else /*IEEE_Arith*/ 484219557Sdas word0(&rv) = Big0; 485219557Sdas word1(&rv) = Big1; 486112158Sdas#endif /*IEEE_Arith*/ 487219557Sdas range_err: 488219557Sdas if (bd0) { 489219557Sdas Bfree(bb); 490219557Sdas Bfree(bd); 491219557Sdas Bfree(bs); 492219557Sdas Bfree(bd0); 493219557Sdas Bfree(delta); 494219557Sdas } 495219557Sdas#ifndef NO_ERRNO 496219557Sdas errno = ERANGE; 497219557Sdas#endif 498112158Sdas goto ret; 499112158Sdas } 500112158Sdas e1 >>= 4; 501112158Sdas for(j = 0; e1 > 1; j++, e1 >>= 1) 502112158Sdas if (e1 & 1) 503219557Sdas dval(&rv) *= bigtens[j]; 504112158Sdas /* The last multiplication could overflow. */ 505219557Sdas word0(&rv) -= P*Exp_msk1; 506219557Sdas dval(&rv) *= bigtens[j]; 507219557Sdas if ((z = word0(&rv) & Exp_mask) 508112158Sdas > Exp_msk1*(DBL_MAX_EXP+Bias-P)) 509112158Sdas goto ovfl; 510112158Sdas if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { 511112158Sdas /* set to largest number */ 512112158Sdas /* (Can't trust DBL_MAX) */ 513219557Sdas word0(&rv) = Big0; 514219557Sdas word1(&rv) = Big1; 515112158Sdas } 516112158Sdas else 517219557Sdas word0(&rv) += P*Exp_msk1; 518112158Sdas } 519112158Sdas } 520112158Sdas else if (e1 < 0) { 521112158Sdas e1 = -e1; 522112158Sdas if ( (i = e1 & 15) !=0) 523219557Sdas dval(&rv) /= tens[i]; 524112158Sdas if (e1 >>= 4) { 525112158Sdas if (e1 >= 1 << n_bigtens) 526112158Sdas goto undfl; 527112158Sdas#ifdef Avoid_Underflow 528112158Sdas if (e1 & Scale_Bit) 529112158Sdas scale = 2*P; 530112158Sdas for(j = 0; e1 > 0; j++, e1 >>= 1) 531112158Sdas if (e1 & 1) 532219557Sdas dval(&rv) *= tinytens[j]; 533219557Sdas if (scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) 534112158Sdas >> Exp_shift)) > 0) { 535112158Sdas /* scaled rv is denormal; zap j low bits */ 536112158Sdas if (j >= 32) { 537219557Sdas word1(&rv) = 0; 538112158Sdas if (j >= 53) 539219557Sdas word0(&rv) = (P+2)*Exp_msk1; 540112158Sdas else 541219557Sdas word0(&rv) &= 0xffffffff << (j-32); 542112158Sdas } 543112158Sdas else 544219557Sdas word1(&rv) &= 0xffffffff << j; 545112158Sdas } 546112158Sdas#else 547112158Sdas for(j = 0; e1 > 1; j++, e1 >>= 1) 548112158Sdas if (e1 & 1) 549219557Sdas dval(&rv) *= tinytens[j]; 550112158Sdas /* The last multiplication could underflow. */ 551219557Sdas dval(&rv0) = dval(&rv); 552219557Sdas dval(&rv) *= tinytens[j]; 553219557Sdas if (!dval(&rv)) { 554219557Sdas dval(&rv) = 2.*dval(&rv0); 555219557Sdas dval(&rv) *= tinytens[j]; 556112158Sdas#endif 557219557Sdas if (!dval(&rv)) { 558112158Sdas undfl: 559219557Sdas dval(&rv) = 0.; 560219557Sdas goto range_err; 561112158Sdas } 562112158Sdas#ifndef Avoid_Underflow 563219557Sdas word0(&rv) = Tiny0; 564219557Sdas word1(&rv) = Tiny1; 565112158Sdas /* The refinement below will clean 566112158Sdas * this approximation up. 567112158Sdas */ 568112158Sdas } 569112158Sdas#endif 570112158Sdas } 571112158Sdas } 572112158Sdas 573112158Sdas /* Now the hard part -- adjusting rv to the correct value.*/ 574112158Sdas 575112158Sdas /* Put digits into bd: true value = bd * 10^e */ 576112158Sdas 577187808Sdas bd0 = s2b(s0, nd0, nd, y, dplen); 578112158Sdas 579112158Sdas for(;;) { 580112158Sdas bd = Balloc(bd0->k); 581112158Sdas Bcopy(bd, bd0); 582219557Sdas bb = d2b(dval(&rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ 583112158Sdas bs = i2b(1); 584112158Sdas 585112158Sdas if (e >= 0) { 586112158Sdas bb2 = bb5 = 0; 587112158Sdas bd2 = bd5 = e; 588112158Sdas } 589112158Sdas else { 590112158Sdas bb2 = bb5 = -e; 591112158Sdas bd2 = bd5 = 0; 592112158Sdas } 593112158Sdas if (bbe >= 0) 594112158Sdas bb2 += bbe; 595112158Sdas else 596112158Sdas bd2 -= bbe; 597112158Sdas bs2 = bb2; 598112158Sdas#ifdef Honor_FLT_ROUNDS 599182709Sdas if (Rounding != 1) 600112158Sdas bs2++; 601112158Sdas#endif 602112158Sdas#ifdef Avoid_Underflow 603219557Sdas Lsb = LSB; 604219557Sdas Lsb1 = 0; 605112158Sdas j = bbe - scale; 606112158Sdas i = j + bbbits - 1; /* logb(rv) */ 607219557Sdas j = P + 1 - bbbits; 608219557Sdas if (i < Emin) { /* denormal */ 609219557Sdas i = Emin - i; 610219557Sdas j -= i; 611219557Sdas if (i < 32) 612219557Sdas Lsb <<= i; 613219557Sdas else 614219557Sdas Lsb1 = Lsb << (i-32); 615219557Sdas } 616112158Sdas#else /*Avoid_Underflow*/ 617112158Sdas#ifdef Sudden_Underflow 618112158Sdas#ifdef IBM 619112158Sdas j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); 620112158Sdas#else 621112158Sdas j = P + 1 - bbbits; 622112158Sdas#endif 623112158Sdas#else /*Sudden_Underflow*/ 624112158Sdas j = bbe; 625219557Sdas i = j + bbbits - 1; /* logb(&rv) */ 626112158Sdas if (i < Emin) /* denormal */ 627112158Sdas j += P - Emin; 628112158Sdas else 629112158Sdas j = P + 1 - bbbits; 630112158Sdas#endif /*Sudden_Underflow*/ 631112158Sdas#endif /*Avoid_Underflow*/ 632112158Sdas bb2 += j; 633112158Sdas bd2 += j; 634112158Sdas#ifdef Avoid_Underflow 635112158Sdas bd2 += scale; 636112158Sdas#endif 637112158Sdas i = bb2 < bd2 ? bb2 : bd2; 638112158Sdas if (i > bs2) 639112158Sdas i = bs2; 640112158Sdas if (i > 0) { 641112158Sdas bb2 -= i; 642112158Sdas bd2 -= i; 643112158Sdas bs2 -= i; 644112158Sdas } 645112158Sdas if (bb5 > 0) { 646112158Sdas bs = pow5mult(bs, bb5); 647112158Sdas bb1 = mult(bs, bb); 648112158Sdas Bfree(bb); 649112158Sdas bb = bb1; 650112158Sdas } 651112158Sdas if (bb2 > 0) 652112158Sdas bb = lshift(bb, bb2); 653112158Sdas if (bd5 > 0) 654112158Sdas bd = pow5mult(bd, bd5); 655112158Sdas if (bd2 > 0) 656112158Sdas bd = lshift(bd, bd2); 657112158Sdas if (bs2 > 0) 658112158Sdas bs = lshift(bs, bs2); 659112158Sdas delta = diff(bb, bd); 660112158Sdas dsign = delta->sign; 661112158Sdas delta->sign = 0; 662112158Sdas i = cmp(delta, bs); 663112158Sdas#ifdef Honor_FLT_ROUNDS 664182709Sdas if (Rounding != 1) { 665112158Sdas if (i < 0) { 666112158Sdas /* Error is less than an ulp */ 667112158Sdas if (!delta->x[0] && delta->wds <= 1) { 668112158Sdas /* exact */ 669112158Sdas#ifdef SET_INEXACT 670112158Sdas inexact = 0; 671112158Sdas#endif 672112158Sdas break; 673112158Sdas } 674182709Sdas if (Rounding) { 675112158Sdas if (dsign) { 676219557Sdas dval(&adj) = 1.; 677112158Sdas goto apply_adj; 678112158Sdas } 679112158Sdas } 680112158Sdas else if (!dsign) { 681219557Sdas dval(&adj) = -1.; 682219557Sdas if (!word1(&rv) 683219557Sdas && !(word0(&rv) & Frac_mask)) { 684219557Sdas y = word0(&rv) & Exp_mask; 685112158Sdas#ifdef Avoid_Underflow 686112158Sdas if (!scale || y > 2*P*Exp_msk1) 687112158Sdas#else 688112158Sdas if (y) 689112158Sdas#endif 690112158Sdas { 691112158Sdas delta = lshift(delta,Log2P); 692112158Sdas if (cmp(delta, bs) <= 0) 693219557Sdas dval(&adj) = -0.5; 694112158Sdas } 695112158Sdas } 696112158Sdas apply_adj: 697112158Sdas#ifdef Avoid_Underflow 698219557Sdas if (scale && (y = word0(&rv) & Exp_mask) 699112158Sdas <= 2*P*Exp_msk1) 700219557Sdas word0(&adj) += (2*P+1)*Exp_msk1 - y; 701112158Sdas#else 702112158Sdas#ifdef Sudden_Underflow 703219557Sdas if ((word0(&rv) & Exp_mask) <= 704112158Sdas P*Exp_msk1) { 705219557Sdas word0(&rv) += P*Exp_msk1; 706219557Sdas dval(&rv) += adj*ulp(&rv); 707219557Sdas word0(&rv) -= P*Exp_msk1; 708112158Sdas } 709112158Sdas else 710112158Sdas#endif /*Sudden_Underflow*/ 711112158Sdas#endif /*Avoid_Underflow*/ 712219557Sdas dval(&rv) += adj.d*ulp(&rv); 713112158Sdas } 714112158Sdas break; 715112158Sdas } 716219557Sdas dval(&adj) = ratio(delta, bs); 717219557Sdas if (adj.d < 1.) 718219557Sdas dval(&adj) = 1.; 719219557Sdas if (adj.d <= 0x7ffffffe) { 720219557Sdas /* dval(&adj) = Rounding ? ceil(&adj) : floor(&adj); */ 721219557Sdas y = adj.d; 722219557Sdas if (y != adj.d) { 723182709Sdas if (!((Rounding>>1) ^ dsign)) 724112158Sdas y++; 725219557Sdas dval(&adj) = y; 726112158Sdas } 727112158Sdas } 728112158Sdas#ifdef Avoid_Underflow 729219557Sdas if (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) 730219557Sdas word0(&adj) += (2*P+1)*Exp_msk1 - y; 731112158Sdas#else 732112158Sdas#ifdef Sudden_Underflow 733219557Sdas if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { 734219557Sdas word0(&rv) += P*Exp_msk1; 735219557Sdas dval(&adj) *= ulp(&rv); 736112158Sdas if (dsign) 737219557Sdas dval(&rv) += adj; 738112158Sdas else 739219557Sdas dval(&rv) -= adj; 740219557Sdas word0(&rv) -= P*Exp_msk1; 741112158Sdas goto cont; 742112158Sdas } 743112158Sdas#endif /*Sudden_Underflow*/ 744112158Sdas#endif /*Avoid_Underflow*/ 745219557Sdas dval(&adj) *= ulp(&rv); 746182709Sdas if (dsign) { 747219557Sdas if (word0(&rv) == Big0 && word1(&rv) == Big1) 748182709Sdas goto ovfl; 749219557Sdas dval(&rv) += adj.d; 750182709Sdas } 751112158Sdas else 752219557Sdas dval(&rv) -= adj.d; 753112158Sdas goto cont; 754112158Sdas } 755112158Sdas#endif /*Honor_FLT_ROUNDS*/ 756112158Sdas 757112158Sdas if (i < 0) { 758112158Sdas /* Error is less than half an ulp -- check for 759112158Sdas * special case of mantissa a power of two. 760112158Sdas */ 761219557Sdas if (dsign || word1(&rv) || word0(&rv) & Bndry_mask 762112158Sdas#ifdef IEEE_Arith 763112158Sdas#ifdef Avoid_Underflow 764219557Sdas || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 765112158Sdas#else 766219557Sdas || (word0(&rv) & Exp_mask) <= Exp_msk1 767112158Sdas#endif 768112158Sdas#endif 769112158Sdas ) { 770112158Sdas#ifdef SET_INEXACT 771112158Sdas if (!delta->x[0] && delta->wds <= 1) 772112158Sdas inexact = 0; 773112158Sdas#endif 774112158Sdas break; 775112158Sdas } 776112158Sdas if (!delta->x[0] && delta->wds <= 1) { 777112158Sdas /* exact result */ 778112158Sdas#ifdef SET_INEXACT 779112158Sdas inexact = 0; 780112158Sdas#endif 781112158Sdas break; 782112158Sdas } 783112158Sdas delta = lshift(delta,Log2P); 784112158Sdas if (cmp(delta, bs) > 0) 785112158Sdas goto drop_down; 786112158Sdas break; 787112158Sdas } 788112158Sdas if (i == 0) { 789112158Sdas /* exactly half-way between */ 790112158Sdas if (dsign) { 791219557Sdas if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 792219557Sdas && word1(&rv) == ( 793112158Sdas#ifdef Avoid_Underflow 794219557Sdas (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) 795112158Sdas ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : 796112158Sdas#endif 797112158Sdas 0xffffffff)) { 798112158Sdas /*boundary case -- increment exponent*/ 799219557Sdas if (word0(&rv) == Big0 && word1(&rv) == Big1) 800219557Sdas goto ovfl; 801219557Sdas word0(&rv) = (word0(&rv) & Exp_mask) 802112158Sdas + Exp_msk1 803112158Sdas#ifdef IBM 804112158Sdas | Exp_msk1 >> 4 805112158Sdas#endif 806112158Sdas ; 807219557Sdas word1(&rv) = 0; 808112158Sdas#ifdef Avoid_Underflow 809112158Sdas dsign = 0; 810112158Sdas#endif 811112158Sdas break; 812112158Sdas } 813112158Sdas } 814219557Sdas else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { 815112158Sdas drop_down: 816112158Sdas /* boundary case -- decrement exponent */ 817112158Sdas#ifdef Sudden_Underflow /*{{*/ 818219557Sdas L = word0(&rv) & Exp_mask; 819112158Sdas#ifdef IBM 820112158Sdas if (L < Exp_msk1) 821112158Sdas#else 822112158Sdas#ifdef Avoid_Underflow 823112158Sdas if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) 824112158Sdas#else 825112158Sdas if (L <= Exp_msk1) 826112158Sdas#endif /*Avoid_Underflow*/ 827112158Sdas#endif /*IBM*/ 828112158Sdas goto undfl; 829112158Sdas L -= Exp_msk1; 830112158Sdas#else /*Sudden_Underflow}{*/ 831112158Sdas#ifdef Avoid_Underflow 832112158Sdas if (scale) { 833219557Sdas L = word0(&rv) & Exp_mask; 834112158Sdas if (L <= (2*P+1)*Exp_msk1) { 835112158Sdas if (L > (P+2)*Exp_msk1) 836112158Sdas /* round even ==> */ 837112158Sdas /* accept rv */ 838112158Sdas break; 839112158Sdas /* rv = smallest denormal */ 840112158Sdas goto undfl; 841112158Sdas } 842112158Sdas } 843112158Sdas#endif /*Avoid_Underflow*/ 844219557Sdas L = (word0(&rv) & Exp_mask) - Exp_msk1; 845182709Sdas#endif /*Sudden_Underflow}}*/ 846219557Sdas word0(&rv) = L | Bndry_mask1; 847219557Sdas word1(&rv) = 0xffffffff; 848112158Sdas#ifdef IBM 849112158Sdas goto cont; 850112158Sdas#else 851112158Sdas break; 852112158Sdas#endif 853112158Sdas } 854112158Sdas#ifndef ROUND_BIASED 855219557Sdas#ifdef Avoid_Underflow 856219557Sdas if (Lsb1) { 857219557Sdas if (!(word0(&rv) & Lsb1)) 858219557Sdas break; 859219557Sdas } 860219557Sdas else if (!(word1(&rv) & Lsb)) 861112158Sdas break; 862219557Sdas#else 863219557Sdas if (!(word1(&rv) & LSB)) 864219557Sdas break; 865112158Sdas#endif 866219557Sdas#endif 867112158Sdas if (dsign) 868219557Sdas#ifdef Avoid_Underflow 869219557Sdas dval(&rv) += sulp(&rv, scale); 870219557Sdas#else 871219557Sdas dval(&rv) += ulp(&rv); 872219557Sdas#endif 873112158Sdas#ifndef ROUND_BIASED 874112158Sdas else { 875219557Sdas#ifdef Avoid_Underflow 876219557Sdas dval(&rv) -= sulp(&rv, scale); 877219557Sdas#else 878219557Sdas dval(&rv) -= ulp(&rv); 879219557Sdas#endif 880112158Sdas#ifndef Sudden_Underflow 881219557Sdas if (!dval(&rv)) 882112158Sdas goto undfl; 883112158Sdas#endif 884112158Sdas } 885112158Sdas#ifdef Avoid_Underflow 886112158Sdas dsign = 1 - dsign; 887112158Sdas#endif 888112158Sdas#endif 889112158Sdas break; 890112158Sdas } 891112158Sdas if ((aadj = ratio(delta, bs)) <= 2.) { 892112158Sdas if (dsign) 893219557Sdas aadj = dval(&aadj1) = 1.; 894219557Sdas else if (word1(&rv) || word0(&rv) & Bndry_mask) { 895112158Sdas#ifndef Sudden_Underflow 896219557Sdas if (word1(&rv) == Tiny1 && !word0(&rv)) 897112158Sdas goto undfl; 898112158Sdas#endif 899112158Sdas aadj = 1.; 900219557Sdas dval(&aadj1) = -1.; 901112158Sdas } 902112158Sdas else { 903112158Sdas /* special case -- power of FLT_RADIX to be */ 904112158Sdas /* rounded down... */ 905112158Sdas 906112158Sdas if (aadj < 2./FLT_RADIX) 907112158Sdas aadj = 1./FLT_RADIX; 908112158Sdas else 909112158Sdas aadj *= 0.5; 910219557Sdas dval(&aadj1) = -aadj; 911112158Sdas } 912112158Sdas } 913112158Sdas else { 914112158Sdas aadj *= 0.5; 915219557Sdas dval(&aadj1) = dsign ? aadj : -aadj; 916112158Sdas#ifdef Check_FLT_ROUNDS 917112158Sdas switch(Rounding) { 918112158Sdas case 2: /* towards +infinity */ 919219557Sdas dval(&aadj1) -= 0.5; 920112158Sdas break; 921112158Sdas case 0: /* towards 0 */ 922112158Sdas case 3: /* towards -infinity */ 923219557Sdas dval(&aadj1) += 0.5; 924112158Sdas } 925112158Sdas#else 926112158Sdas if (Flt_Rounds == 0) 927219557Sdas dval(&aadj1) += 0.5; 928112158Sdas#endif /*Check_FLT_ROUNDS*/ 929112158Sdas } 930219557Sdas y = word0(&rv) & Exp_mask; 931112158Sdas 932112158Sdas /* Check for overflow */ 933112158Sdas 934112158Sdas if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { 935219557Sdas dval(&rv0) = dval(&rv); 936219557Sdas word0(&rv) -= P*Exp_msk1; 937219557Sdas dval(&adj) = dval(&aadj1) * ulp(&rv); 938219557Sdas dval(&rv) += dval(&adj); 939219557Sdas if ((word0(&rv) & Exp_mask) >= 940112158Sdas Exp_msk1*(DBL_MAX_EXP+Bias-P)) { 941219557Sdas if (word0(&rv0) == Big0 && word1(&rv0) == Big1) 942112158Sdas goto ovfl; 943219557Sdas word0(&rv) = Big0; 944219557Sdas word1(&rv) = Big1; 945112158Sdas goto cont; 946112158Sdas } 947112158Sdas else 948219557Sdas word0(&rv) += P*Exp_msk1; 949112158Sdas } 950112158Sdas else { 951112158Sdas#ifdef Avoid_Underflow 952112158Sdas if (scale && y <= 2*P*Exp_msk1) { 953112158Sdas if (aadj <= 0x7fffffff) { 954112158Sdas if ((z = aadj) <= 0) 955112158Sdas z = 1; 956112158Sdas aadj = z; 957219557Sdas dval(&aadj1) = dsign ? aadj : -aadj; 958112158Sdas } 959219557Sdas word0(&aadj1) += (2*P+1)*Exp_msk1 - y; 960112158Sdas } 961219557Sdas dval(&adj) = dval(&aadj1) * ulp(&rv); 962219557Sdas dval(&rv) += dval(&adj); 963112158Sdas#else 964112158Sdas#ifdef Sudden_Underflow 965219557Sdas if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { 966219557Sdas dval(&rv0) = dval(&rv); 967219557Sdas word0(&rv) += P*Exp_msk1; 968219557Sdas dval(&adj) = dval(&aadj1) * ulp(&rv); 969219557Sdas dval(&rv) += adj; 970112158Sdas#ifdef IBM 971219557Sdas if ((word0(&rv) & Exp_mask) < P*Exp_msk1) 972112158Sdas#else 973219557Sdas if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) 974112158Sdas#endif 975112158Sdas { 976219557Sdas if (word0(&rv0) == Tiny0 977219557Sdas && word1(&rv0) == Tiny1) 978112158Sdas goto undfl; 979219557Sdas word0(&rv) = Tiny0; 980219557Sdas word1(&rv) = Tiny1; 981112158Sdas goto cont; 982112158Sdas } 983112158Sdas else 984219557Sdas word0(&rv) -= P*Exp_msk1; 985112158Sdas } 986112158Sdas else { 987219557Sdas dval(&adj) = dval(&aadj1) * ulp(&rv); 988219557Sdas dval(&rv) += adj; 989112158Sdas } 990112158Sdas#else /*Sudden_Underflow*/ 991219557Sdas /* Compute dval(&adj) so that the IEEE rounding rules will 992219557Sdas * correctly round rv + dval(&adj) in some half-way cases. 993219557Sdas * If rv * ulp(&rv) is denormalized (i.e., 994112158Sdas * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid 995112158Sdas * trouble from bits lost to denormalization; 996112158Sdas * example: 1.2e-307 . 997112158Sdas */ 998112158Sdas if (y <= (P-1)*Exp_msk1 && aadj > 1.) { 999219557Sdas dval(&aadj1) = (double)(int)(aadj + 0.5); 1000112158Sdas if (!dsign) 1001219557Sdas dval(&aadj1) = -dval(&aadj1); 1002112158Sdas } 1003219557Sdas dval(&adj) = dval(&aadj1) * ulp(&rv); 1004219557Sdas dval(&rv) += adj; 1005112158Sdas#endif /*Sudden_Underflow*/ 1006112158Sdas#endif /*Avoid_Underflow*/ 1007112158Sdas } 1008219557Sdas z = word0(&rv) & Exp_mask; 1009112158Sdas#ifndef SET_INEXACT 1010112158Sdas#ifdef Avoid_Underflow 1011112158Sdas if (!scale) 1012112158Sdas#endif 1013112158Sdas if (y == z) { 1014112158Sdas /* Can we stop now? */ 1015112158Sdas L = (Long)aadj; 1016112158Sdas aadj -= L; 1017112158Sdas /* The tolerances below are conservative. */ 1018219557Sdas if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) { 1019112158Sdas if (aadj < .4999999 || aadj > .5000001) 1020112158Sdas break; 1021112158Sdas } 1022112158Sdas else if (aadj < .4999999/FLT_RADIX) 1023112158Sdas break; 1024112158Sdas } 1025112158Sdas#endif 1026112158Sdas cont: 1027112158Sdas Bfree(bb); 1028112158Sdas Bfree(bd); 1029112158Sdas Bfree(bs); 1030112158Sdas Bfree(delta); 1031112158Sdas } 1032219557Sdas Bfree(bb); 1033219557Sdas Bfree(bd); 1034219557Sdas Bfree(bs); 1035219557Sdas Bfree(bd0); 1036219557Sdas Bfree(delta); 1037112158Sdas#ifdef SET_INEXACT 1038112158Sdas if (inexact) { 1039112158Sdas if (!oldinexact) { 1040219557Sdas word0(&rv0) = Exp_1 + (70 << Exp_shift); 1041219557Sdas word1(&rv0) = 0; 1042219557Sdas dval(&rv0) += 1.; 1043112158Sdas } 1044112158Sdas } 1045112158Sdas else if (!oldinexact) 1046112158Sdas clear_inexact(); 1047112158Sdas#endif 1048112158Sdas#ifdef Avoid_Underflow 1049112158Sdas if (scale) { 1050219557Sdas word0(&rv0) = Exp_1 - 2*P*Exp_msk1; 1051219557Sdas word1(&rv0) = 0; 1052219557Sdas dval(&rv) *= dval(&rv0); 1053112158Sdas#ifndef NO_ERRNO 1054112158Sdas /* try to avoid the bug of testing an 8087 register value */ 1055187808Sdas#ifdef IEEE_Arith 1056219557Sdas if (!(word0(&rv) & Exp_mask)) 1057187808Sdas#else 1058219557Sdas if (word0(&rv) == 0 && word1(&rv) == 0) 1059187808Sdas#endif 1060112158Sdas errno = ERANGE; 1061112158Sdas#endif 1062112158Sdas } 1063112158Sdas#endif /* Avoid_Underflow */ 1064112158Sdas#ifdef SET_INEXACT 1065219557Sdas if (inexact && !(word0(&rv) & Exp_mask)) { 1066112158Sdas /* set underflow bit */ 1067219557Sdas dval(&rv0) = 1e-300; 1068219557Sdas dval(&rv0) *= dval(&rv0); 1069112158Sdas } 1070112158Sdas#endif 1071112158Sdas ret: 1072112158Sdas if (se) 1073112158Sdas *se = (char *)s; 1074219557Sdas return sign ? -dval(&rv) : dval(&rv); 1075112158Sdas } 1076112158Sdas 1077235785Stheraven double 1078235785Stheravenstrtod 1079235785Stheraven#ifdef KR_headers 1080235785Stheraven (s00, se, loc) CONST char *s00; char **se; locale_t 1081235785Stheraven#else 1082235785Stheraven (CONST char *s00, char **se) 1083235785Stheraven#endif 1084235785Stheraven{ 1085235785Stheraven return strtod_l(s00, se, __get_locale()); 1086235785Stheraven} 1087235785Stheraven 1088