123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- /****************************************************************
- The author of this software is David M. Gay.
- Copyright (C) 1998 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 "."). */
- #include "gdtoaimp.h"
- #ifdef USE_LOCALE
- #include "locale.h"
- #endif
- int
- #ifdef KR_headers
- gethex(sp, fpi, exp, bp, sign)
- CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
- #else
- gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
- #endif
- {
- Bigint *b;
- CONST unsigned char *decpt, *s0, *s, *s1;
- int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
- ULong L, lostbits, *x;
- Long e, e1;
- #ifdef USE_LOCALE
- int i;
- #ifdef NO_LOCALE_CACHE
- const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
- #else
- const unsigned char *decimalpoint;
- static unsigned char *decimalpoint_cache;
- if (!(s0 = decimalpoint_cache)) {
- s0 = (unsigned char*)localeconv()->decimal_point;
- if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
- strlcpy(decimalpoint_cache, s0, strlen(s0) + 1);
- s0 = decimalpoint_cache;
- }
- }
- decimalpoint = s0;
- #endif
- #endif
- if (!hexdig['0'])
- hexdig_init_D2A();
- *bp = 0;
- havedig = 0;
- s0 = *(CONST unsigned char **)sp + 2;
- while(s0[havedig] == '0')
- havedig++;
- s0 += havedig;
- s = s0;
- decpt = 0;
- zret = 0;
- e = 0;
- if (hexdig[*s])
- havedig++;
- else {
- zret = 1;
- #ifdef USE_LOCALE
- for(i = 0; decimalpoint[i]; ++i) {
- if (s[i] != decimalpoint[i])
- goto pcheck;
- }
- decpt = s += i;
- #else
- if (*s != '.')
- goto pcheck;
- decpt = ++s;
- #endif
- if (!hexdig[*s])
- goto pcheck;
- while(*s == '0')
- s++;
- if (hexdig[*s])
- zret = 0;
- havedig = 1;
- s0 = s;
- }
- while(hexdig[*s])
- s++;
- #ifdef USE_LOCALE
- if (*s == *decimalpoint && !decpt) {
- for(i = 1; decimalpoint[i]; ++i) {
- if (s[i] != decimalpoint[i])
- goto pcheck;
- }
- decpt = s += i;
- #else
- if (*s == '.' && !decpt) {
- decpt = ++s;
- #endif
- while(hexdig[*s])
- s++;
- }/*}*/
- if (decpt)
- e = -(((Long)(s-decpt)) << 2);
- pcheck:
- s1 = s;
- big = esign = 0;
- switch(*s) {
- case 'p':
- case 'P':
- switch(*++s) {
- case '-':
- esign = 1;
- /* no break */
- case '+':
- s++;
- }
- if ((n = hexdig[*s]) == 0 || n > 0x19) {
- s = s1;
- break;
- }
- e1 = n - 0x10;
- while((n = hexdig[*++s]) !=0 && n <= 0x19) {
- if (e1 & 0xf8000000)
- big = 1;
- e1 = 10*e1 + n - 0x10;
- }
- if (esign)
- e1 = -e1;
- e += e1;
- }
- *sp = (char*)s;
- if (!havedig)
- *sp = (char*)s0 - 1;
- if (zret)
- return STRTOG_Zero;
- if (big) {
- if (esign) {
- switch(fpi->rounding) {
- case FPI_Round_up:
- if (sign)
- break;
- goto ret_tiny;
- case FPI_Round_down:
- if (!sign)
- break;
- goto ret_tiny;
- }
- goto retz;
- ret_tiny:
- b = Balloc(0);
- if (b == NULL)
- return (STRTOG_NoMemory);
- b->wds = 1;
- b->x[0] = 1;
- goto dret;
- }
- switch(fpi->rounding) {
- case FPI_Round_near:
- goto ovfl1;
- case FPI_Round_up:
- if (!sign)
- goto ovfl1;
- goto ret_big;
- case FPI_Round_down:
- if (sign)
- goto ovfl1;
- goto ret_big;
- }
- ret_big:
- nbits = fpi->nbits;
- n0 = n = nbits >> kshift;
- if (nbits & kmask)
- ++n;
- for(j = n, k = 0; j >>= 1; ++k);
- *bp = b = Balloc(k);
- if (*bp == NULL)
- return (STRTOG_NoMemory);
- b->wds = n;
- for(j = 0; j < n0; ++j)
- b->x[j] = ALL_ON;
- if (n > n0)
- b->x[j] = ULbits >> (ULbits - (nbits & kmask));
- *exp = fpi->emin;
- return STRTOG_Normal | STRTOG_Inexlo;
- }
- n = s1 - s0 - 1;
- for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
- k++;
- b = Balloc(k);
- if (b == NULL)
- return (STRTOG_NoMemory);
- x = b->x;
- n = 0;
- L = 0;
- #ifdef USE_LOCALE
- for(i = 0; decimalpoint[i+1]; ++i);
- #endif
- while(s1 > s0) {
- #ifdef USE_LOCALE
- if (*--s1 == decimalpoint[i]) {
- s1 -= i;
- continue;
- }
- #else
- if (*--s1 == '.')
- continue;
- #endif
- if (n == ULbits) {
- *x++ = L;
- L = 0;
- n = 0;
- }
- L |= (hexdig[*s1] & 0x0f) << n;
- n += 4;
- }
- *x++ = L;
- b->wds = n = x - b->x;
- n = ULbits*n - hi0bits(L);
- nbits = fpi->nbits;
- lostbits = 0;
- x = b->x;
- if (n > nbits) {
- n -= nbits;
- if (any_on(b,n)) {
- lostbits = 1;
- k = n - 1;
- if (x[k>>kshift] & 1 << (k & kmask)) {
- lostbits = 2;
- if (k > 0 && any_on(b,k))
- lostbits = 3;
- }
- }
- rshift(b, n);
- e += n;
- }
- else if (n < nbits) {
- n = nbits - n;
- b = lshift(b, n);
- if (b == NULL)
- return (STRTOG_NoMemory);
- e -= n;
- x = b->x;
- }
- if (e > fpi->emax) {
- ovfl:
- Bfree(b);
- ovfl1:
- #ifndef NO_ERRNO
- errno = ERANGE;
- #endif
- return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
- }
- irv = STRTOG_Normal;
- if (e < fpi->emin) {
- irv = STRTOG_Denormal;
- n = fpi->emin - e;
- if (n >= nbits) {
- switch (fpi->rounding) {
- case FPI_Round_near:
- if (n == nbits && (n < 2 || any_on(b,n-1)))
- goto one_bit;
- break;
- case FPI_Round_up:
- if (!sign)
- goto one_bit;
- break;
- case FPI_Round_down:
- if (sign) {
- one_bit:
- x[0] = b->wds = 1;
- dret:
- *bp = b;
- *exp = fpi->emin;
- #ifndef NO_ERRNO
- errno = ERANGE;
- #endif
- return STRTOG_Denormal | STRTOG_Inexhi
- | STRTOG_Underflow;
- }
- }
- Bfree(b);
- retz:
- #ifndef NO_ERRNO
- errno = ERANGE;
- #endif
- return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
- }
- k = n - 1;
- if (lostbits)
- lostbits = 1;
- else if (k > 0)
- lostbits = any_on(b,k);
- if (x[k>>kshift] & 1 << (k & kmask))
- lostbits |= 2;
- nbits -= n;
- rshift(b,n);
- e = fpi->emin;
- }
- if (lostbits) {
- up = 0;
- switch(fpi->rounding) {
- case FPI_Round_zero:
- break;
- case FPI_Round_near:
- if (lostbits & 2
- && (lostbits | x[0]) & 1)
- up = 1;
- break;
- case FPI_Round_up:
- up = 1 - sign;
- break;
- case FPI_Round_down:
- up = sign;
- }
- if (up) {
- k = b->wds;
- b = increment(b);
- if (b == NULL)
- return (STRTOG_NoMemory);
- x = b->x;
- if (irv == STRTOG_Denormal) {
- if (nbits == fpi->nbits - 1
- && x[nbits >> kshift] & 1 << (nbits & kmask))
- irv = STRTOG_Normal;
- }
- else if (b->wds > k
- || ((n = nbits & kmask) !=0
- && hi0bits(x[k-1]) < 32-n)) {
- rshift(b,1);
- if (++e > fpi->emax)
- goto ovfl;
- }
- irv |= STRTOG_Inexhi;
- }
- else
- irv |= STRTOG_Inexlo;
- }
- *bp = b;
- *exp = e;
- return irv;
- }
|