gethex.c revision 219557
133965Sjdp/**************************************************************** 260484Sobrien 360484SobrienThe author of this software is David M. Gay. 433965Sjdp 533965SjdpCopyright (C) 1998 by Lucent Technologies 633965SjdpAll Rights Reserved 733965Sjdp 833965SjdpPermission to use, copy, modify, and distribute this software and 933965Sjdpits documentation for any purpose and without fee is hereby 1033965Sjdpgranted, provided that the above copyright notice appear in all 1133965Sjdpcopies and that both that the copyright notice and this 1233965Sjdppermission notice and warranty disclaimer appear in supporting 1333965Sjdpdocumentation, and that the name of Lucent or any of its entities 1433965Sjdpnot be used in advertising or publicity pertaining to 1533965Sjdpdistribution of the software without specific, written prior 1633965Sjdppermission. 1733965Sjdp 1833965SjdpLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1933965SjdpINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 2033965SjdpIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 2133965SjdpSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 2233965SjdpWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 2333965SjdpIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2433965SjdpARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 2533965SjdpTHIS SOFTWARE. 2633965Sjdp 2733965Sjdp****************************************************************/ 2833965Sjdp 2933965Sjdp/* Please send bug reports to David M. Gay (dmg at acm dot org, 3033965Sjdp * with " at " changed at "@" and " dot " changed to "."). */ 3133965Sjdp 3233965Sjdp#include "gdtoaimp.h" 3333965Sjdp 3433965Sjdp#ifdef USE_LOCALE 3533965Sjdp#include "locale.h" 3633965Sjdp#endif 3733965Sjdp 3833965Sjdp int 3933965Sjdp#ifdef KR_headers 4033965Sjdpgethex(sp, fpi, exp, bp, sign) 4133965Sjdp CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; 4233965Sjdp#else 4333965Sjdpgethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) 4433965Sjdp#endif 4533965Sjdp{ 4633965Sjdp Bigint *b; 4733965Sjdp CONST unsigned char *decpt, *s0, *s, *s1; 4833965Sjdp int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; 4933965Sjdp ULong L, lostbits, *x; 5033965Sjdp Long e, e1; 5133965Sjdp#ifdef USE_LOCALE 5233965Sjdp int i; 5333965Sjdp#ifdef NO_LOCALE_CACHE 5433965Sjdp const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point; 5533965Sjdp#else 5633965Sjdp const unsigned char *decimalpoint; 5733965Sjdp static unsigned char *decimalpoint_cache; 5833965Sjdp if (!(s0 = decimalpoint_cache)) { 5933965Sjdp s0 = (unsigned char*)localeconv()->decimal_point; 6033965Sjdp if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { 6133965Sjdp strcpy(decimalpoint_cache, s0); 6233965Sjdp s0 = decimalpoint_cache; 6333965Sjdp } 6433965Sjdp } 6533965Sjdp decimalpoint = s0; 6633965Sjdp#endif 6733965Sjdp#endif 6833965Sjdp 6933965Sjdp if (!hexdig['0']) 7033965Sjdp hexdig_init_D2A(); 7133965Sjdp *bp = 0; 7233965Sjdp havedig = 0; 7333965Sjdp s0 = *(CONST unsigned char **)sp + 2; 7433965Sjdp while(s0[havedig] == '0') 7533965Sjdp havedig++; 7633965Sjdp s0 += havedig; 7733965Sjdp s = s0; 7833965Sjdp decpt = 0; 7933965Sjdp zret = 0; 8033965Sjdp e = 0; 8133965Sjdp if (hexdig[*s]) 8233965Sjdp havedig++; 8333965Sjdp else { 8433965Sjdp zret = 1; 8533965Sjdp#ifdef USE_LOCALE 8633965Sjdp for(i = 0; decimalpoint[i]; ++i) { 8733965Sjdp if (s[i] != decimalpoint[i]) 8833965Sjdp goto pcheck; 8960484Sobrien } 9060484Sobrien decpt = s += i; 9160484Sobrien#else 9260484Sobrien if (*s != '.') 9360484Sobrien goto pcheck; 9460484Sobrien decpt = ++s; 9560484Sobrien#endif 9660484Sobrien if (!hexdig[*s]) 9760484Sobrien goto pcheck; 9860484Sobrien while(*s == '0') 9933965Sjdp s++; 10033965Sjdp if (hexdig[*s]) 10133965Sjdp zret = 0; 10233965Sjdp havedig = 1; 10333965Sjdp s0 = s; 10433965Sjdp } 10533965Sjdp while(hexdig[*s]) 10633965Sjdp s++; 10733965Sjdp#ifdef USE_LOCALE 10833965Sjdp if (*s == *decimalpoint && !decpt) { 10933965Sjdp for(i = 1; decimalpoint[i]; ++i) { 11060484Sobrien if (s[i] != decimalpoint[i]) 11160484Sobrien goto pcheck; 11260484Sobrien } 11360484Sobrien decpt = s += i; 11460484Sobrien#else 11560484Sobrien if (*s == '.' && !decpt) { 11660484Sobrien decpt = ++s; 11760484Sobrien#endif 11860484Sobrien while(hexdig[*s]) 11960484Sobrien s++; 12060484Sobrien }/*}*/ 12133965Sjdp if (decpt) 12260484Sobrien e = -(((Long)(s-decpt)) << 2); 12360484Sobrien pcheck: 12460484Sobrien s1 = s; 12560484Sobrien big = esign = 0; 12660484Sobrien switch(*s) { 12760484Sobrien case 'p': 12833965Sjdp case 'P': 12933965Sjdp switch(*++s) { 13033965Sjdp case '-': 13133965Sjdp esign = 1; 13233965Sjdp /* no break */ 13333965Sjdp case '+': 13433965Sjdp s++; 13533965Sjdp } 13633965Sjdp if ((n = hexdig[*s]) == 0 || n > 0x19) { 13733965Sjdp s = s1; 13833965Sjdp break; 13933965Sjdp } 14033965Sjdp e1 = n - 0x10; 14133965Sjdp while((n = hexdig[*++s]) !=0 && n <= 0x19) { 14233965Sjdp if (e1 & 0xf8000000) 14333965Sjdp big = 1; 14433965Sjdp e1 = 10*e1 + n - 0x10; 14533965Sjdp } 14633965Sjdp if (esign) 14760484Sobrien e1 = -e1; 14860484Sobrien e += e1; 14960484Sobrien } 15060484Sobrien *sp = (char*)s; 15160484Sobrien if (!havedig) 15260484Sobrien *sp = (char*)s0 - 1; 15360484Sobrien if (zret) 15460484Sobrien return STRTOG_Zero; 15560484Sobrien if (big) { 15660484Sobrien if (esign) { 15733965Sjdp switch(fpi->rounding) { 15833965Sjdp case FPI_Round_up: 15933965Sjdp if (sign) 16060484Sobrien break; 16133965Sjdp goto ret_tiny; 16233965Sjdp case FPI_Round_down: 16360484Sobrien if (!sign) 16460484Sobrien break; 16560484Sobrien goto ret_tiny; 16633965Sjdp } 16733965Sjdp goto retz; 16833965Sjdp ret_tiny: 16933965Sjdp b = Balloc(0); 17033965Sjdp b->wds = 1; 17133965Sjdp b->x[0] = 1; 17233965Sjdp goto dret; 17333965Sjdp } 17433965Sjdp switch(fpi->rounding) { 17533965Sjdp case FPI_Round_near: 17660484Sobrien goto ovfl1; 17760484Sobrien case FPI_Round_up: 17833965Sjdp if (!sign) 17960484Sobrien goto ovfl1; 18033965Sjdp goto ret_big; 18160484Sobrien case FPI_Round_down: 18233965Sjdp if (sign) 18360484Sobrien goto ovfl1; 18433965Sjdp goto ret_big; 18560484Sobrien } 18633965Sjdp ret_big: 18760484Sobrien nbits = fpi->nbits; 18833965Sjdp n0 = n = nbits >> kshift; 18960484Sobrien if (nbits & kmask) 19060484Sobrien ++n; 19160484Sobrien for(j = n, k = 0; j >>= 1; ++k); 19260484Sobrien *bp = b = Balloc(k); 19360484Sobrien b->wds = n; 19460484Sobrien for(j = 0; j < n0; ++j) 19533965Sjdp b->x[j] = ALL_ON; 19633965Sjdp if (n > n0) 19760484Sobrien b->x[j] = ULbits >> (ULbits - (nbits & kmask)); 19860484Sobrien *exp = fpi->emin; 19960484Sobrien return STRTOG_Normal | STRTOG_Inexlo; 20060484Sobrien } 20160484Sobrien n = s1 - s0 - 1; 20260484Sobrien for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) 20360484Sobrien k++; 20460484Sobrien b = Balloc(k); 20560484Sobrien x = b->x; 20660484Sobrien n = 0; 20760484Sobrien L = 0; 20860484Sobrien#ifdef USE_LOCALE 20960484Sobrien for(i = 0; decimalpoint[i+1]; ++i); 21060484Sobrien#endif 21177298Sobrien while(s1 > s0) { 21260484Sobrien#ifdef USE_LOCALE 21360484Sobrien if (*--s1 == decimalpoint[i]) { 21460484Sobrien s1 -= i; 21560484Sobrien continue; 21633965Sjdp } 21733965Sjdp#else 21833965Sjdp if (*--s1 == '.') 21933965Sjdp continue; 22033965Sjdp#endif 22133965Sjdp if (n == ULbits) { 22233965Sjdp *x++ = L; 22333965Sjdp L = 0; 22433965Sjdp n = 0; 22533965Sjdp } 22633965Sjdp L |= (hexdig[*s1] & 0x0f) << n; 22733965Sjdp n += 4; 22833965Sjdp } 22933965Sjdp *x++ = L; 23033965Sjdp b->wds = n = x - b->x; 23133965Sjdp n = ULbits*n - hi0bits(L); 23233965Sjdp nbits = fpi->nbits; 23333965Sjdp lostbits = 0; 23433965Sjdp x = b->x; 23533965Sjdp if (n > nbits) { 23633965Sjdp n -= nbits; 23733965Sjdp if (any_on(b,n)) { 23833965Sjdp lostbits = 1; 23933965Sjdp k = n - 1; 24033965Sjdp if (x[k>>kshift] & 1 << (k & kmask)) { 24133965Sjdp lostbits = 2; 24233965Sjdp if (k > 0 && any_on(b,k)) 24333965Sjdp lostbits = 3; 24460484Sobrien } 24560484Sobrien } 24677298Sobrien rshift(b, n); 24777298Sobrien e += n; 24877298Sobrien } 24933965Sjdp else if (n < nbits) { 25033965Sjdp n = nbits - n; 25133965Sjdp b = lshift(b, n); 25233965Sjdp e -= n; 25333965Sjdp x = b->x; 25433965Sjdp } 25533965Sjdp if (e > fpi->emax) { 25633965Sjdp ovfl: 25733965Sjdp Bfree(b); 25833965Sjdp ovfl1: 25933965Sjdp#ifndef NO_ERRNO 26033965Sjdp errno = ERANGE; 26133965Sjdp#endif 26233965Sjdp return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 26333965Sjdp } 26433965Sjdp irv = STRTOG_Normal; 26533965Sjdp if (e < fpi->emin) { 26633965Sjdp irv = STRTOG_Denormal; 26733965Sjdp n = fpi->emin - e; 26833965Sjdp if (n >= nbits) { 26933965Sjdp switch (fpi->rounding) { 27033965Sjdp case FPI_Round_near: 27133965Sjdp if (n == nbits && (n < 2 || any_on(b,n-1))) 27233965Sjdp goto one_bit; 27333965Sjdp break; 27433965Sjdp case FPI_Round_up: 27533965Sjdp if (!sign) 27660484Sobrien goto one_bit; 27760484Sobrien break; 27860484Sobrien case FPI_Round_down: 27960484Sobrien if (sign) { 28060484Sobrien one_bit: 28160484Sobrien x[0] = b->wds = 1; 28260484Sobrien dret: 28333965Sjdp *bp = b; 28433965Sjdp *exp = fpi->emin; 28533965Sjdp#ifndef NO_ERRNO 28633965Sjdp errno = ERANGE; 28733965Sjdp#endif 28833965Sjdp return STRTOG_Denormal | STRTOG_Inexhi 28933965Sjdp | STRTOG_Underflow; 29033965Sjdp } 29133965Sjdp } 29233965Sjdp Bfree(b); 29360484Sobrien retz: 29460484Sobrien#ifndef NO_ERRNO 29560484Sobrien errno = ERANGE; 29660484Sobrien#endif 29760484Sobrien return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 29860484Sobrien } 29960484Sobrien k = n - 1; 30060484Sobrien if (lostbits) 30160484Sobrien lostbits = 1; 30260484Sobrien else if (k > 0) 30360484Sobrien lostbits = any_on(b,k); 30460484Sobrien if (x[k>>kshift] & 1 << (k & kmask)) 30560484Sobrien lostbits |= 2; 30660484Sobrien nbits -= n; 30760484Sobrien rshift(b,n); 30860484Sobrien e = fpi->emin; 30960484Sobrien } 31060484Sobrien if (lostbits) { 31160484Sobrien up = 0; 31260484Sobrien switch(fpi->rounding) { 31360484Sobrien case FPI_Round_zero: 31460484Sobrien break; 31560484Sobrien case FPI_Round_near: 31660484Sobrien if (lostbits & 2 31760484Sobrien && (lostbits | x[0]) & 1) 31860484Sobrien up = 1; 31933965Sjdp break; 32033965Sjdp case FPI_Round_up: 32133965Sjdp up = 1 - sign; 32233965Sjdp break; 32333965Sjdp case FPI_Round_down: 32433965Sjdp up = sign; 32533965Sjdp } 32633965Sjdp if (up) { 32733965Sjdp k = b->wds; 32833965Sjdp b = increment(b); 32933965Sjdp x = b->x; 33033965Sjdp if (irv == STRTOG_Denormal) { 33133965Sjdp if (nbits == fpi->nbits - 1 33233965Sjdp && x[nbits >> kshift] & 1 << (nbits & kmask)) 33333965Sjdp irv = STRTOG_Normal; 33433965Sjdp } 33533965Sjdp else if (b->wds > k 33633965Sjdp || ((n = nbits & kmask) !=0 33733965Sjdp && hi0bits(x[k-1]) < 32-n)) { 33833965Sjdp rshift(b,1); 33933965Sjdp if (++e > fpi->emax) 34033965Sjdp goto ovfl; 34133965Sjdp } 34233965Sjdp irv |= STRTOG_Inexhi; 34333965Sjdp } 34433965Sjdp else 34533965Sjdp irv |= STRTOG_Inexlo; 34633965Sjdp } 34733965Sjdp *bp = b; 34833965Sjdp *exp = e; 34933965Sjdp return irv; 35033965Sjdp } 35133965Sjdp