| /** @file | |
| Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials are licensed and made available under | |
| the terms and conditions of the BSD License that accompanies this distribution. | |
| The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| ***************************************************************** | |
| The author of this software is David M. Gay. | |
| Copyright (C) 1998-2001 by Lucent Technologies | |
| All Rights Reserved | |
| Permission to use, copy, modify, and distribute this software and | |
| its documentation for any purpose and without fee is hereby | |
| granted, provided that the above copyright notice appear in all | |
| copies and that both that the copyright notice and this | |
| permission notice and warranty disclaimer appear in supporting | |
| documentation, and that the name of Lucent or any of its entities | |
| not be used in advertising or publicity pertaining to | |
| distribution of the software without specific, written prior | |
| permission. | |
| LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
| INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. | |
| IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY | |
| SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |
| IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| THIS SOFTWARE. | |
| Please send bug reports to David M. Gay (dmg at acm dot org, | |
| with " at " changed at "@" and " dot " changed to "."). | |
| ***************************************************************** | |
| NetBSD: strtodg.c,v 1.5.14.1 2008/04/08 21:10:55 jdc Exp | |
| **/ | |
| #include <LibConfig.h> | |
| #include "gdtoaimp.h" | |
| #ifdef USE_LOCALE | |
| #include "locale.h" | |
| #endif | |
| #if defined(_MSC_VER) | |
| // Disable warnings about assignment within conditional expressions. | |
| #pragma warning ( disable : 4706 ) | |
| #endif | |
| static CONST int | |
| fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21, | |
| 24, 26, 28, 31, 33, 35, 38, 40, 42, 45, | |
| 47, 49, 52 | |
| #ifdef VAX | |
| , 54, 56 | |
| #endif | |
| }; | |
| Bigint * | |
| increment(Bigint *b) | |
| { | |
| ULong *x, *xe; | |
| Bigint *b1; | |
| #ifdef Pack_16 | |
| ULong carry = 1, y; | |
| #endif | |
| x = b->x; | |
| xe = x + b->wds; | |
| #ifdef Pack_32 | |
| do { | |
| if (*x < (ULong)0xffffffffL) { | |
| ++*x; | |
| return b; | |
| } | |
| *x++ = 0; | |
| } while(x < xe); | |
| #else | |
| do { | |
| y = *x + carry; | |
| carry = y >> 16; | |
| *x++ = y & 0xffff; | |
| if (!carry) | |
| return b; | |
| } while(x < xe); | |
| if (carry) | |
| #endif | |
| { | |
| if (b->wds >= b->maxwds) { | |
| b1 = Balloc(b->k+1); | |
| if (b1 == NULL) | |
| return NULL; | |
| Bcopy(b1,b); | |
| Bfree(b); | |
| b = b1; | |
| } | |
| b->x[b->wds++] = 1; | |
| } | |
| return b; | |
| } | |
| int | |
| decrement(Bigint *b) | |
| { | |
| ULong *x, *xe; | |
| #ifdef Pack_16 | |
| ULong borrow = 1, y; | |
| #endif | |
| x = b->x; | |
| xe = x + b->wds; | |
| #ifdef Pack_32 | |
| do { | |
| if (*x) { | |
| --*x; | |
| break; | |
| } | |
| *x++ = 0xffffffffUL; | |
| } | |
| while(x < xe); | |
| #else | |
| do { | |
| y = *x - borrow; | |
| borrow = (y & 0x10000) >> 16; | |
| *x++ = y & 0xffff; | |
| } while(borrow && x < xe); | |
| #endif | |
| return STRTOG_Inexlo; | |
| } | |
| static int | |
| all_on(CONST Bigint *b, int n) | |
| { | |
| CONST ULong *x, *xe; | |
| x = b->x; | |
| xe = x + ((unsigned int)n >> kshift); | |
| while(x < xe) | |
| if ((*x++ & ALL_ON) != ALL_ON) | |
| return 0; | |
| if (n &= kmask) | |
| return ((*x | (ALL_ON << n)) & ALL_ON) == ALL_ON; | |
| return 1; | |
| } | |
| Bigint * | |
| set_ones(Bigint *b, int n) | |
| { | |
| int k; | |
| ULong *x, *xe; | |
| k = (unsigned int)(n + ((1 << kshift) - 1)) >> kshift; | |
| if (b->k < k) { | |
| Bfree(b); | |
| b = Balloc(k); | |
| if (b == NULL) | |
| return NULL; | |
| } | |
| k = (unsigned int)n >> kshift; | |
| if (n &= kmask) | |
| k++; | |
| b->wds = k; | |
| x = b->x; | |
| xe = x + k; | |
| while(x < xe) | |
| *x++ = ALL_ON; | |
| if (n) | |
| x[-1] >>= ULbits - n; | |
| return b; | |
| } | |
| static int | |
| rvOK ( | |
| double d, CONST FPI *fpi, Long *expt, ULong *bits, int exact, int rd, int *irv | |
| ) | |
| { | |
| Bigint *b; | |
| ULong carry, inex, lostbits; | |
| int bdif, e, j, k, k1, nb, rv; | |
| carry = rv = 0; | |
| b = d2b(d, &e, &bdif); | |
| bdif -= nb = fpi->nbits; | |
| e += bdif; | |
| if (bdif <= 0) { | |
| if (exact) | |
| goto trunc; | |
| goto ret; | |
| } | |
| if (P == nb) { | |
| if ( | |
| #ifndef IMPRECISE_INEXACT | |
| exact && | |
| #endif | |
| fpi->rounding == | |
| #ifdef RND_PRODQUOT | |
| FPI_Round_near | |
| #else | |
| Flt_Rounds | |
| #endif | |
| ) goto trunc; | |
| goto ret; | |
| } | |
| switch(rd) { | |
| case 1: | |
| goto trunc; | |
| case 2: | |
| break; | |
| default: /* round near */ | |
| k = bdif - 1; | |
| if (!k) { | |
| if (!exact) | |
| goto ret; | |
| if (b->x[0] & 2) | |
| break; | |
| goto trunc; | |
| } | |
| if (b->x[(unsigned int)k>>kshift] & ((ULong)1 << (k & kmask))) | |
| break; | |
| goto trunc; | |
| } | |
| /* "break" cases: round up 1 bit, then truncate; bdif > 0 */ | |
| carry = 1; | |
| trunc: | |
| inex = lostbits = 0; | |
| if (bdif > 0) { | |
| if ( (lostbits = any_on(b, bdif)) !=0) | |
| inex = STRTOG_Inexlo; | |
| rshift(b, bdif); | |
| if (carry) { | |
| inex = STRTOG_Inexhi; | |
| b = increment(b); | |
| if ( (j = nb & kmask) !=0) | |
| j = ULbits - j; | |
| if (hi0bits(b->x[b->wds - 1]) != j) { | |
| if (!lostbits) | |
| lostbits = b->x[0] & 1; | |
| rshift(b, 1); | |
| e++; | |
| } | |
| } | |
| } | |
| else if (bdif < 0) | |
| b = lshift(b, -bdif); | |
| if (e < fpi->emin) { | |
| k = fpi->emin - e; | |
| e = fpi->emin; | |
| if (k > nb || fpi->sudden_underflow) { | |
| inex = b->wds = 0; | |
| *irv = STRTOG_Underflow | STRTOG_Inexlo; | |
| } | |
| else { | |
| k1 = k - 1; | |
| if (k1 > 0 && !lostbits) | |
| lostbits = any_on(b, k1); | |
| if (!lostbits && !exact) | |
| goto ret; | |
| lostbits |= | |
| carry = b->x[(unsigned int)k1>>kshift] & | |
| (ULong)(1 << ((unsigned int)k1 & kmask)); | |
| rshift(b, k); | |
| *irv = STRTOG_Denormal; | |
| if (carry) { | |
| b = increment(b); | |
| inex = STRTOG_Inexhi | STRTOG_Underflow; | |
| } | |
| else if (lostbits) | |
| inex = STRTOG_Inexlo | STRTOG_Underflow; | |
| } | |
| } | |
| else if (e > fpi->emax) { | |
| e = fpi->emax + 1; | |
| *irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; | |
| #ifndef NO_ERRNO | |
| errno = ERANGE; | |
| #endif | |
| inex = b->wds = 0; | |
| } | |
| *expt = e; | |
| copybits(bits, nb, b); | |
| *irv |= inex; | |
| rv = 1; | |
| ret: | |
| Bfree(b); | |
| return rv; | |
| } | |
| static int | |
| mantbits(double d) | |
| { | |
| ULong L; | |
| if ( (L = word1(d)) !=0) | |
| return P - lo0bits(&L); | |
| L = word0(d) | Exp_msk1; | |
| return P - 32 - lo0bits(&L); | |
| } | |
| int | |
| strtodg ( | |
| CONST char *s00, char **se, CONST FPI *fpi, Long *expt, ULong *bits | |
| ) | |
| { | |
| int abe = 0, abits = 0, asub; | |
| int bb0, bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, denorm; | |
| int dsign, e, e1, e2, emin, esign, finished, i, inex, irv; | |
| int j, k, nbits, nd, nd0, nf, nz, nz0, rd, rvbits, rve, rve1, sign; | |
| int sudden_underflow = 0; /* pacify gcc */ | |
| CONST char *s, *s0, *s1; | |
| double adj, adj0, rv, tol; | |
| Long L; | |
| ULong y, z; | |
| Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0; | |
| e2 = 0; /* XXX gcc */ | |
| irv = STRTOG_Zero; | |
| denorm = sign = nz0 = nz = 0; | |
| dval(rv) = 0.; | |
| rvb = 0; | |
| nbits = fpi->nbits; | |
| for(s = s00;;s++) switch(*s) { | |
| case '-': | |
| sign = 1; | |
| /* FALLTHROUGH */ | |
| case '+': | |
| if (*++s) | |
| goto break2; | |
| /* FALLTHROUGH */ | |
| case 0: | |
| sign = 0; | |
| irv = STRTOG_NoNumber; | |
| s = s00; | |
| goto ret; | |
| case '\t': | |
| case '\n': | |
| case '\v': | |
| case '\f': | |
| case '\r': | |
| case ' ': | |
| continue; | |
| default: | |
| goto break2; | |
| } | |
| break2: | |
| if (*s == '0') { | |
| #ifndef NO_HEX_FP | |
| switch(s[1]) { | |
| case 'x': | |
| case 'X': | |
| irv = gethex(&s, fpi, expt, &rvb, sign); | |
| if (irv == STRTOG_NoNumber) { | |
| s = s00; | |
| sign = 0; | |
| } | |
| goto ret; | |
| } | |
| #endif | |
| nz0 = 1; | |
| while(*++s == '0') ; | |
| if (!*s) | |
| goto ret; | |
| } | |
| sudden_underflow = fpi->sudden_underflow; | |
| s0 = s; | |
| y = z = 0; | |
| for(decpt = nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) | |
| if (nd < 9) | |
| y = 10*y + c - '0'; | |
| else if (nd < 16) | |
| z = 10*z + c - '0'; | |
| nd0 = nd; | |
| #ifdef USE_LOCALE | |
| if (c == *localeconv()->decimal_point) | |
| #else | |
| if (c == '.') | |
| #endif | |
| { | |
| decpt = 1; | |
| c = *++s; | |
| if (!nd) { | |
| for(; c == '0'; c = *++s) | |
| nz++; | |
| if (c > '0' && c <= '9') { | |
| s0 = s; | |
| nf += nz; | |
| nz = 0; | |
| goto have_dig; | |
| } | |
| goto dig_done; | |
| } | |
| for(; c >= '0' && c <= '9'; c = *++s) { | |
| have_dig: | |
| nz++; | |
| if (c -= '0') { | |
| nf += nz; | |
| for(i = 1; i < nz; i++) | |
| if (nd++ < 9) | |
| y *= 10; | |
| else if (nd <= DBL_DIG + 1) | |
| z *= 10; | |
| if (nd++ < 9) | |
| y = 10*y + c; | |
| else if (nd <= DBL_DIG + 1) | |
| z = 10*z + c; | |
| nz = 0; | |
| } | |
| } | |
| } | |
| dig_done: | |
| e = 0; | |
| if (c == 'e' || c == 'E') { | |
| if (!nd && !nz && !nz0) { | |
| irv = STRTOG_NoNumber; | |
| s = s00; | |
| goto ret; | |
| } | |
| s00 = s; | |
| esign = 0; | |
| switch(c = *++s) { | |
| case '-': | |
| esign = 1; | |
| /* FALLTHROUGH */ | |
| case '+': | |
| c = *++s; | |
| } | |
| if (c >= '0' && c <= '9') { | |
| while(c == '0') | |
| c = *++s; | |
| if (c > '0' && c <= '9') { | |
| L = c - '0'; | |
| s1 = s; | |
| while((c = *++s) >= '0' && c <= '9') | |
| L = 10*L + c - '0'; | |
| if (s - s1 > 8 || L > 19999) | |
| /* Avoid confusion from exponents | |
| * so large that e might overflow. | |
| */ | |
| e = 19999; /* safe for 16 bit ints */ | |
| else | |
| e = (int)L; | |
| if (esign) | |
| e = -e; | |
| } | |
| else | |
| e = 0; | |
| } | |
| else | |
| s = s00; | |
| } | |
| if (!nd) { | |
| if (!nz && !nz0) { | |
| #ifdef INFNAN_CHECK | |
| /* Check for Nan and Infinity */ | |
| if (!decpt) | |
| switch(c) { | |
| case 'i': | |
| case 'I': | |
| if (match(&s,"nf")) { | |
| --s; | |
| if (!match(&s,"inity")) | |
| ++s; | |
| irv = STRTOG_Infinite; | |
| goto infnanexp; | |
| } | |
| break; | |
| case 'n': | |
| case 'N': | |
| if (match(&s, "an")) { | |
| irv = STRTOG_NaN; | |
| *expt = fpi->emax + 1; | |
| #ifndef No_Hex_NaN | |
| if (*s == '(') /*)*/ | |
| irv = hexnan(&s, fpi, bits); | |
| #endif | |
| goto infnanexp; | |
| } | |
| } | |
| #endif /* INFNAN_CHECK */ | |
| irv = STRTOG_NoNumber; | |
| s = s00; | |
| } | |
| goto ret; | |
| } | |
| irv = STRTOG_Normal; | |
| e1 = e -= nf; | |
| rd = 0; | |
| switch(fpi->rounding & 3) { | |
| case FPI_Round_up: | |
| rd = 2 - sign; | |
| break; | |
| case FPI_Round_zero: | |
| rd = 1; | |
| break; | |
| case FPI_Round_down: | |
| rd = 1 + sign; | |
| } | |
| /* Now we have nd0 digits, starting at s0, followed by a | |
| * decimal point, followed by nd-nd0 digits. The number we're | |
| * after is the integer represented by those digits times | |
| * 10**e */ | |
| if (!nd0) | |
| nd0 = nd; | |
| k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; | |
| dval(rv) = (double)y; | |
| if (k > 9) | |
| dval(rv) = tens[k - 9] * dval(rv) + z; | |
| bd0 = 0; | |
| if (nbits <= P && nd <= DBL_DIG) { | |
| if (!e) { | |
| if (rvOK(dval(rv), fpi, expt, bits, 1, rd, &irv)) | |
| goto ret; | |
| } | |
| else if (e > 0) { | |
| if (e <= Ten_pmax) { | |
| i = fivesbits[e] + mantbits(dval(rv)) <= P; | |
| /* rv = */ rounded_product(dval(rv), tens[e]); | |
| if (rvOK(dval(rv), fpi, expt, bits, i, rd, &irv)) | |
| goto ret; | |
| e1 -= e; | |
| goto rv_notOK; | |
| } | |
| i = DBL_DIG - nd; | |
| if (e <= Ten_pmax + i) { | |
| /* A fancier test would sometimes let us do | |
| * this for larger i values. | |
| */ | |
| e2 = e - i; | |
| e1 -= i; | |
| dval(rv) *= tens[i]; | |
| /* rv = */ rounded_product(dval(rv), tens[e2]); | |
| if (rvOK(dval(rv), fpi, expt, bits, 0, rd, &irv)) | |
| goto ret; | |
| e1 -= e2; | |
| } | |
| } | |
| #ifndef Inaccurate_Divide | |
| else if (e >= -Ten_pmax) { | |
| /* rv = */ rounded_quotient(dval(rv), tens[-e]); | |
| if (rvOK(dval(rv), fpi, expt, bits, 0, rd, &irv)) | |
| goto ret; | |
| e1 -= e; | |
| } | |
| #endif | |
| } | |
| rv_notOK: | |
| e1 += nd - k; | |
| /* Get starting approximation = rv * 10**e1 */ | |
| e2 = 0; | |
| if (e1 > 0) { | |
| if ( (i = e1 & 15) !=0) | |
| dval(rv) *= tens[i]; | |
| if (e1 &= ~15) { | |
| e1 = (unsigned int)e1 >> 4; | |
| while(e1 >= (1 << (n_bigtens-1))) { | |
| e2 += (unsigned int)((word0(rv) & Exp_mask) | |
| >> Exp_shift1) - Bias; | |
| word0(rv) &= ~Exp_mask; | |
| word0(rv) |= Bias << Exp_shift1; | |
| dval(rv) *= bigtens[n_bigtens-1]; | |
| e1 -= 1 << (n_bigtens-1); | |
| } | |
| e2 += (unsigned int)((word0(rv) & Exp_mask) >> Exp_shift1) - Bias; | |
| word0(rv) &= ~Exp_mask; | |
| word0(rv) |= Bias << Exp_shift1; | |
| for(j = 0; e1 > 0; j++, e1 = (unsigned int)e1 >> 1) | |
| if (e1 & 1) | |
| dval(rv) *= bigtens[j]; | |
| } | |
| } | |
| else if (e1 < 0) { | |
| e1 = -e1; | |
| if ( (i = e1 & 15) !=0) | |
| dval(rv) /= tens[i]; | |
| if (e1 &= ~15) { | |
| e1 = (unsigned int)e1 >> 4; | |
| while(e1 >= (1 << (n_bigtens-1))) { | |
| e2 += (unsigned int)((word0(rv) & Exp_mask) | |
| >> Exp_shift1) - Bias; | |
| word0(rv) &= ~Exp_mask; | |
| word0(rv) |= Bias << Exp_shift1; | |
| dval(rv) *= tinytens[n_bigtens-1]; | |
| e1 -= 1 << (n_bigtens-1); | |
| } | |
| e2 += (unsigned int)((word0(rv) & Exp_mask) >> Exp_shift1) - Bias; | |
| word0(rv) &= ~Exp_mask; | |
| word0(rv) |= Bias << Exp_shift1; | |
| for(j = 0; e1 > 0; j++, e1 = (unsigned int)e1 >> 1) | |
| if (e1 & 1) | |
| dval(rv) *= tinytens[j]; | |
| } | |
| } | |
| rvb = d2b(dval(rv), &rve, &rvbits); /* rv = rvb * 2^rve */ | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| rve += e2; | |
| if ((j = rvbits - nbits) > 0) { | |
| rshift(rvb, j); | |
| rvbits = nbits; | |
| rve += j; | |
| } | |
| bb0 = 0; /* trailing zero bits in rvb */ | |
| e2 = rve + rvbits - nbits; | |
| if (e2 > fpi->emax + 1) | |
| goto huge; | |
| rve1 = rve + rvbits - nbits; | |
| if (e2 < (emin = fpi->emin)) { | |
| denorm = 1; | |
| j = rve - emin; | |
| if (j > 0) { | |
| rvb = lshift(rvb, j); | |
| rvbits += j; | |
| } | |
| else if (j < 0) { | |
| rvbits += j; | |
| if (rvbits <= 0) { | |
| if (rvbits < -1) { | |
| ufl: | |
| rvb->wds = 0; | |
| rvb->x[0] = 0; | |
| *expt = emin; | |
| irv = STRTOG_Underflow | STRTOG_Inexlo; | |
| goto ret; | |
| } | |
| rvb->x[0] = rvb->wds = rvbits = 1; | |
| } | |
| else | |
| rshift(rvb, -j); | |
| } | |
| rve = rve1 = emin; | |
| if (sudden_underflow && e2 + 1 < emin) | |
| goto ufl; | |
| } | |
| /* Now the hard part -- adjusting rv to the correct value.*/ | |
| /* Put digits into bd: true value = bd * 10^e */ | |
| bd0 = s2b(s0, nd0, nd, y); | |
| for(;;) { | |
| bd = Balloc(bd0->k); | |
| if (bd == NULL) | |
| return STRTOG_NoMemory; | |
| Bcopy(bd, bd0); | |
| bb = Balloc(rvb->k); | |
| if (bb == NULL) | |
| return STRTOG_NoMemory; | |
| Bcopy(bb, rvb); | |
| bbbits = rvbits - bb0; | |
| bbe = rve + bb0; | |
| bs = i2b(1); | |
| if (bs == NULL) | |
| return STRTOG_NoMemory; | |
| if (e >= 0) { | |
| bb2 = bb5 = 0; | |
| bd2 = bd5 = e; | |
| } | |
| else { | |
| bb2 = bb5 = -e; | |
| bd2 = bd5 = 0; | |
| } | |
| if (bbe >= 0) | |
| bb2 += bbe; | |
| else | |
| bd2 -= bbe; | |
| bs2 = bb2; | |
| j = nbits + 1 - bbbits; | |
| i = bbe + bbbits - nbits; | |
| if (i < emin) /* denormal */ | |
| j += i - emin; | |
| bb2 += j; | |
| bd2 += j; | |
| i = bb2 < bd2 ? bb2 : bd2; | |
| if (i > bs2) | |
| i = bs2; | |
| if (i > 0) { | |
| bb2 -= i; | |
| bd2 -= i; | |
| bs2 -= i; | |
| } | |
| if (bb5 > 0) { | |
| bs = pow5mult(bs, bb5); | |
| if (bs == NULL) | |
| return STRTOG_NoMemory; | |
| bb1 = mult(bs, bb); | |
| if (bb1 == NULL) | |
| return STRTOG_NoMemory; | |
| Bfree(bb); | |
| bb = bb1; | |
| } | |
| bb2 -= bb0; | |
| if (bb2 > 0) { | |
| bb = lshift(bb, bb2); | |
| if (bb == NULL) | |
| return STRTOG_NoMemory; | |
| } | |
| else if (bb2 < 0) | |
| rshift(bb, -bb2); | |
| if (bd5 > 0) { | |
| bd = pow5mult(bd, bd5); | |
| if (bd == NULL) | |
| return STRTOG_NoMemory; | |
| } | |
| if (bd2 > 0) { | |
| bd = lshift(bd, bd2); | |
| if (bd == NULL) | |
| return STRTOG_NoMemory; | |
| } | |
| if (bs2 > 0) { | |
| bs = lshift(bs, bs2); | |
| if (bs == NULL) | |
| return STRTOG_NoMemory; | |
| } | |
| asub = 1; | |
| inex = STRTOG_Inexhi; | |
| delta = diff(bb, bd); | |
| if (delta == NULL) | |
| return STRTOG_NoMemory; | |
| if (delta->wds <= 1 && !delta->x[0]) | |
| break; | |
| dsign = delta->sign; | |
| delta->sign = finished = 0; | |
| L = 0; | |
| i = cmp(delta, bs); | |
| if (rd && i <= 0) { | |
| irv = STRTOG_Normal; | |
| if ( (finished = dsign ^ (rd&1)) !=0) { | |
| if (dsign != 0) { | |
| irv |= STRTOG_Inexhi; | |
| goto adj1; | |
| } | |
| irv |= STRTOG_Inexlo; | |
| if (rve1 == emin) | |
| goto adj1; | |
| for(i = 0, j = nbits; j >= ULbits; | |
| i++, j -= ULbits) { | |
| if (rvb->x[i] & ALL_ON) | |
| goto adj1; | |
| } | |
| if (j > 1 && lo0bits(rvb->x + i) < j - 1) | |
| goto adj1; | |
| rve = rve1 - 1; | |
| rvb = set_ones(rvb, rvbits = nbits); | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| break; | |
| } | |
| irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi; | |
| break; | |
| } | |
| if (i < 0) { | |
| /* Error is less than half an ulp -- check for | |
| * special case of mantissa a power of two. | |
| */ | |
| irv = dsign | |
| ? STRTOG_Normal | STRTOG_Inexlo | |
| : STRTOG_Normal | STRTOG_Inexhi; | |
| if (dsign || bbbits > 1 || denorm || rve1 == emin) | |
| break; | |
| delta = lshift(delta,1); | |
| if (delta == NULL) | |
| return STRTOG_NoMemory; | |
| if (cmp(delta, bs) > 0) { | |
| irv = STRTOG_Normal | STRTOG_Inexlo; | |
| goto drop_down; | |
| } | |
| break; | |
| } | |
| if (i == 0) { | |
| /* exactly half-way between */ | |
| if (dsign) { | |
| if (denorm && all_on(rvb, rvbits)) { | |
| /*boundary case -- increment exponent*/ | |
| rvb->wds = 1; | |
| rvb->x[0] = 1; | |
| rve = emin + nbits - (rvbits = 1); | |
| irv = STRTOG_Normal | STRTOG_Inexhi; | |
| denorm = 0; | |
| break; | |
| } | |
| irv = STRTOG_Normal | STRTOG_Inexlo; | |
| } | |
| else if (bbbits == 1) { | |
| irv = STRTOG_Normal; | |
| drop_down: | |
| /* boundary case -- decrement exponent */ | |
| if (rve1 == emin) { | |
| irv = STRTOG_Normal | STRTOG_Inexhi; | |
| if (rvb->wds == 1 && rvb->x[0] == 1) | |
| sudden_underflow = 1; | |
| break; | |
| } | |
| rve -= nbits; | |
| rvb = set_ones(rvb, rvbits = nbits); | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| break; | |
| } | |
| else | |
| irv = STRTOG_Normal | STRTOG_Inexhi; | |
| if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1)) | |
| break; | |
| if (dsign) { | |
| rvb = increment(rvb); | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| if ( (j = rvbits & kmask) !=0) | |
| j = ULbits - j; | |
| if (hi0bits(rvb->x[(unsigned int)(rvb->wds - 1) | |
| >> kshift]) | |
| != j) | |
| rvbits++; | |
| irv = STRTOG_Normal | STRTOG_Inexhi; | |
| } | |
| else { | |
| if (bbbits == 1) | |
| goto undfl; | |
| decrement(rvb); | |
| irv = STRTOG_Normal | STRTOG_Inexlo; | |
| } | |
| break; | |
| } | |
| if ((dval(adj) = ratio(delta, bs)) <= 2.) { | |
| adj1: | |
| inex = STRTOG_Inexlo; | |
| if (dsign) { | |
| asub = 0; | |
| inex = STRTOG_Inexhi; | |
| } | |
| else if (denorm && bbbits <= 1) { | |
| undfl: | |
| rvb->wds = 0; | |
| rve = emin; | |
| irv = STRTOG_Underflow | STRTOG_Inexlo; | |
| break; | |
| } | |
| adj0 = dval(adj) = 1.; | |
| } | |
| else { | |
| adj0 = dval(adj) *= 0.5; | |
| if (dsign) { | |
| asub = 0; | |
| inex = STRTOG_Inexlo; | |
| } | |
| if (dval(adj) < 2147483647.) { | |
| L = (Long)adj0; | |
| adj0 -= L; | |
| switch(rd) { | |
| case 0: | |
| if (adj0 >= .5) | |
| goto inc_L; | |
| break; | |
| case 1: | |
| if (asub && adj0 > 0.) | |
| goto inc_L; | |
| break; | |
| case 2: | |
| if (!asub && adj0 > 0.) { | |
| inc_L: | |
| L++; | |
| inex = STRTOG_Inexact - inex; | |
| } | |
| } | |
| dval(adj) = (double)L; | |
| } | |
| } | |
| y = rve + rvbits; | |
| /* adj *= ulp(dval(rv)); */ | |
| /* if (asub) rv -= adj; else rv += adj; */ | |
| if (!denorm && rvbits < nbits) { | |
| rvb = lshift(rvb, j = nbits - rvbits); | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| rve -= j; | |
| rvbits = nbits; | |
| } | |
| ab = d2b(dval(adj), &abe, &abits); | |
| if (ab == NULL) | |
| return STRTOG_NoMemory; | |
| if (abe < 0) | |
| rshift(ab, -abe); | |
| else if (abe > 0) | |
| ab = lshift(ab, abe); | |
| rvb0 = rvb; | |
| if (asub) { | |
| /* rv -= adj; */ | |
| j = hi0bits(rvb->x[rvb->wds-1]); | |
| rvb = diff(rvb, ab); | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| k = rvb0->wds - 1; | |
| if (denorm) | |
| /* do nothing */; | |
| else if (rvb->wds <= k | |
| || hi0bits( rvb->x[k]) > | |
| hi0bits(rvb0->x[k])) { | |
| /* unlikely; can only have lost 1 high bit */ | |
| if (rve1 == emin) { | |
| --rvbits; | |
| denorm = 1; | |
| } | |
| else { | |
| rvb = lshift(rvb, 1); | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| --rve; | |
| --rve1; | |
| L = finished = 0; | |
| } | |
| } | |
| } | |
| else { | |
| rvb = sum(rvb, ab); | |
| if (rvb == NULL) | |
| return STRTOG_NoMemory; | |
| k = rvb->wds - 1; | |
| if (k >= rvb0->wds | |
| || hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) { | |
| if (denorm) { | |
| if (++rvbits == nbits) | |
| denorm = 0; | |
| } | |
| else { | |
| rshift(rvb, 1); | |
| rve++; | |
| rve1++; | |
| L = 0; | |
| } | |
| } | |
| } | |
| Bfree(ab); | |
| Bfree(rvb0); | |
| if (finished) | |
| break; | |
| z = rve + rvbits; | |
| if (y == z && L) { | |
| /* Can we stop now? */ | |
| tol = dval(adj) * 5e-16; /* > max rel error */ | |
| dval(adj) = adj0 - .5; | |
| if (dval(adj) < -tol) { | |
| if (adj0 > tol) { | |
| irv |= inex; | |
| break; | |
| } | |
| } | |
| else if (dval(adj) > tol && adj0 < 1. - tol) { | |
| irv |= inex; | |
| break; | |
| } | |
| } | |
| bb0 = denorm ? 0 : trailz(rvb); | |
| Bfree(bb); | |
| Bfree(bd); | |
| Bfree(bs); | |
| Bfree(delta); | |
| } | |
| if (!denorm && (j = nbits - rvbits)) { | |
| if (j > 0) | |
| rvb = lshift(rvb, j); | |
| else | |
| rshift(rvb, -j); | |
| rve -= j; | |
| } | |
| *expt = rve; | |
| Bfree(bb); | |
| Bfree(bd); | |
| Bfree(bs); | |
| Bfree(bd0); | |
| Bfree(delta); | |
| if (rve > fpi->emax) { | |
| huge: | |
| rvb->wds = 0; | |
| irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; | |
| #ifndef NO_ERRNO | |
| errno = ERANGE; | |
| #endif | |
| #ifdef INFNAN_CHECK | |
| infnanexp: | |
| #endif | |
| *expt = fpi->emax + 1; | |
| } | |
| ret: | |
| if (denorm) { | |
| if (sudden_underflow) { | |
| rvb->wds = 0; | |
| irv = STRTOG_Underflow | STRTOG_Inexlo; | |
| } | |
| else { | |
| irv = (irv & ~STRTOG_Retmask) | | |
| (rvb->wds > 0 ? STRTOG_Denormal : STRTOG_Zero); | |
| if (irv & STRTOG_Inexact) | |
| irv |= STRTOG_Underflow; | |
| } | |
| } | |
| if (se) | |
| *se = __UNCONST(s); | |
| if (sign) | |
| irv |= STRTOG_Neg; | |
| if (rvb) { | |
| copybits(bits, nbits, rvb); | |
| Bfree(rvb); | |
| } | |
| return irv; | |
| } |