17b36286aSmartynas /****************************************************************
27b36286aSmartynas
37b36286aSmartynas The author of this software is David M. Gay.
47b36286aSmartynas
57b36286aSmartynas Copyright (C) 1998 by Lucent Technologies
67b36286aSmartynas All Rights Reserved
77b36286aSmartynas
87b36286aSmartynas Permission to use, copy, modify, and distribute this software and
97b36286aSmartynas its documentation for any purpose and without fee is hereby
107b36286aSmartynas granted, provided that the above copyright notice appear in all
117b36286aSmartynas copies and that both that the copyright notice and this
127b36286aSmartynas permission notice and warranty disclaimer appear in supporting
137b36286aSmartynas documentation, and that the name of Lucent or any of its entities
147b36286aSmartynas not be used in advertising or publicity pertaining to
157b36286aSmartynas distribution of the software without specific, written prior
167b36286aSmartynas permission.
177b36286aSmartynas
187b36286aSmartynas LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
197b36286aSmartynas INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
207b36286aSmartynas IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
217b36286aSmartynas SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
227b36286aSmartynas WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
237b36286aSmartynas IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
247b36286aSmartynas ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
257b36286aSmartynas THIS SOFTWARE.
267b36286aSmartynas
277b36286aSmartynas ****************************************************************/
287b36286aSmartynas
297b36286aSmartynas /* Please send bug reports to David M. Gay (dmg at acm dot org,
307b36286aSmartynas * with " at " changed at "@" and " dot " changed to "."). */
317b36286aSmartynas
327b36286aSmartynas #include "gdtoaimp.h"
337b36286aSmartynas
347b36286aSmartynas #ifdef USE_LOCALE
357b36286aSmartynas #include "locale.h"
367b36286aSmartynas #endif
377b36286aSmartynas
387b36286aSmartynas int
397b36286aSmartynas #ifdef KR_headers
gethex(sp,fpi,exp,bp,sign)407b36286aSmartynas gethex(sp, fpi, exp, bp, sign)
417b36286aSmartynas CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign;
427b36286aSmartynas #else
437b36286aSmartynas gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign)
447b36286aSmartynas #endif
457b36286aSmartynas {
467b36286aSmartynas Bigint *b;
477b36286aSmartynas CONST unsigned char *decpt, *s0, *s, *s1;
48aad11945Smartynas int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
497b36286aSmartynas ULong L, lostbits, *x;
507b36286aSmartynas Long e, e1;
517b36286aSmartynas #ifdef USE_LOCALE
52aad11945Smartynas int i;
53aad11945Smartynas #ifdef NO_LOCALE_CACHE
54aad11945Smartynas const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point;
557b36286aSmartynas #else
56aad11945Smartynas const unsigned char *decimalpoint;
57aad11945Smartynas static unsigned char *decimalpoint_cache;
58aad11945Smartynas if (!(s0 = decimalpoint_cache)) {
59aad11945Smartynas s0 = (unsigned char*)localeconv()->decimal_point;
60*5b44245bSderaadt decimalpoint_cache = strdup(s0);
61aad11945Smartynas }
62aad11945Smartynas decimalpoint = s0;
63aad11945Smartynas #endif
647b36286aSmartynas #endif
657b36286aSmartynas
667b36286aSmartynas if (!hexdig['0'])
67b3b7ef2eSguenther __hexdig_init_D2A();
68aad11945Smartynas *bp = 0;
697b36286aSmartynas havedig = 0;
707b36286aSmartynas s0 = *(CONST unsigned char **)sp + 2;
717b36286aSmartynas while(s0[havedig] == '0')
727b36286aSmartynas havedig++;
737b36286aSmartynas s0 += havedig;
747b36286aSmartynas s = s0;
757b36286aSmartynas decpt = 0;
767b36286aSmartynas zret = 0;
777b36286aSmartynas e = 0;
78aad11945Smartynas if (hexdig[*s])
79aad11945Smartynas havedig++;
80aad11945Smartynas else {
817b36286aSmartynas zret = 1;
82aad11945Smartynas #ifdef USE_LOCALE
83aad11945Smartynas for(i = 0; decimalpoint[i]; ++i) {
84aad11945Smartynas if (s[i] != decimalpoint[i])
85aad11945Smartynas goto pcheck;
86aad11945Smartynas }
87aad11945Smartynas decpt = s += i;
88aad11945Smartynas #else
89aad11945Smartynas if (*s != '.')
907b36286aSmartynas goto pcheck;
917b36286aSmartynas decpt = ++s;
92aad11945Smartynas #endif
937b36286aSmartynas if (!hexdig[*s])
947b36286aSmartynas goto pcheck;
957b36286aSmartynas while(*s == '0')
967b36286aSmartynas s++;
977b36286aSmartynas if (hexdig[*s])
987b36286aSmartynas zret = 0;
997b36286aSmartynas havedig = 1;
1007b36286aSmartynas s0 = s;
1017b36286aSmartynas }
1027b36286aSmartynas while(hexdig[*s])
1037b36286aSmartynas s++;
104aad11945Smartynas #ifdef USE_LOCALE
105aad11945Smartynas if (*s == *decimalpoint && !decpt) {
106aad11945Smartynas for(i = 1; decimalpoint[i]; ++i) {
107aad11945Smartynas if (s[i] != decimalpoint[i])
108aad11945Smartynas goto pcheck;
109aad11945Smartynas }
110aad11945Smartynas decpt = s += i;
111aad11945Smartynas #else
112aad11945Smartynas if (*s == '.' && !decpt) {
1137b36286aSmartynas decpt = ++s;
114aad11945Smartynas #endif
1157b36286aSmartynas while(hexdig[*s])
1167b36286aSmartynas s++;
117aad11945Smartynas }/*}*/
1187b36286aSmartynas if (decpt)
1197b36286aSmartynas e = -(((Long)(s-decpt)) << 2);
1207b36286aSmartynas pcheck:
1217b36286aSmartynas s1 = s;
122aad11945Smartynas big = esign = 0;
1237b36286aSmartynas switch(*s) {
1247b36286aSmartynas case 'p':
1257b36286aSmartynas case 'P':
1267b36286aSmartynas switch(*++s) {
1277b36286aSmartynas case '-':
1287b36286aSmartynas esign = 1;
1297b36286aSmartynas /* no break */
1307b36286aSmartynas case '+':
1317b36286aSmartynas s++;
1327b36286aSmartynas }
1337b36286aSmartynas if ((n = hexdig[*s]) == 0 || n > 0x19) {
1347b36286aSmartynas s = s1;
1357b36286aSmartynas break;
1367b36286aSmartynas }
1377b36286aSmartynas e1 = n - 0x10;
138aad11945Smartynas while((n = hexdig[*++s]) !=0 && n <= 0x19) {
139aad11945Smartynas if (e1 & 0xf8000000)
140aad11945Smartynas big = 1;
1417b36286aSmartynas e1 = 10*e1 + n - 0x10;
142aad11945Smartynas }
1437b36286aSmartynas if (esign)
1447b36286aSmartynas e1 = -e1;
1457b36286aSmartynas e += e1;
1467b36286aSmartynas }
1477b36286aSmartynas *sp = (char*)s;
1487b36286aSmartynas if (!havedig)
149aad11945Smartynas *sp = (char*)s0 - 1;
150aad11945Smartynas if (zret)
1517b36286aSmartynas return STRTOG_Zero;
152aad11945Smartynas if (big) {
153aad11945Smartynas if (esign) {
154aad11945Smartynas switch(fpi->rounding) {
155aad11945Smartynas case FPI_Round_up:
156aad11945Smartynas if (sign)
157aad11945Smartynas break;
158aad11945Smartynas goto ret_tiny;
159aad11945Smartynas case FPI_Round_down:
160aad11945Smartynas if (!sign)
161aad11945Smartynas break;
162aad11945Smartynas goto ret_tiny;
163aad11945Smartynas }
164aad11945Smartynas goto retz;
165aad11945Smartynas ret_tiny:
166aad11945Smartynas b = Balloc(0);
167384cfdc1Smartynas if (b == NULL)
168384cfdc1Smartynas return (STRTOG_NoMemory);
169aad11945Smartynas b->wds = 1;
170aad11945Smartynas b->x[0] = 1;
171aad11945Smartynas goto dret;
172aad11945Smartynas }
173aad11945Smartynas switch(fpi->rounding) {
174aad11945Smartynas case FPI_Round_near:
175aad11945Smartynas goto ovfl1;
176aad11945Smartynas case FPI_Round_up:
177aad11945Smartynas if (!sign)
178aad11945Smartynas goto ovfl1;
179aad11945Smartynas goto ret_big;
180aad11945Smartynas case FPI_Round_down:
181aad11945Smartynas if (sign)
182aad11945Smartynas goto ovfl1;
183aad11945Smartynas goto ret_big;
184aad11945Smartynas }
185aad11945Smartynas ret_big:
186aad11945Smartynas nbits = fpi->nbits;
187aad11945Smartynas n0 = n = nbits >> kshift;
188aad11945Smartynas if (nbits & kmask)
189aad11945Smartynas ++n;
190aad11945Smartynas for(j = n, k = 0; j >>= 1; ++k);
191aad11945Smartynas *bp = b = Balloc(k);
1921a653cbcSmartynas if (*bp == NULL)
193384cfdc1Smartynas return (STRTOG_NoMemory);
194aad11945Smartynas b->wds = n;
195aad11945Smartynas for(j = 0; j < n0; ++j)
196aad11945Smartynas b->x[j] = ALL_ON;
197aad11945Smartynas if (n > n0)
198aad11945Smartynas b->x[j] = ULbits >> (ULbits - (nbits & kmask));
199aad11945Smartynas *exp = fpi->emin;
200aad11945Smartynas return STRTOG_Normal | STRTOG_Inexlo;
2017b36286aSmartynas }
2027b36286aSmartynas n = s1 - s0 - 1;
2031a653cbcSmartynas for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
2047b36286aSmartynas k++;
2057b36286aSmartynas b = Balloc(k);
206384cfdc1Smartynas if (b == NULL)
207384cfdc1Smartynas return (STRTOG_NoMemory);
2087b36286aSmartynas x = b->x;
2097b36286aSmartynas n = 0;
2107b36286aSmartynas L = 0;
211aad11945Smartynas #ifdef USE_LOCALE
212aad11945Smartynas for(i = 0; decimalpoint[i+1]; ++i);
213aad11945Smartynas #endif
2147b36286aSmartynas while(s1 > s0) {
215aad11945Smartynas #ifdef USE_LOCALE
216aad11945Smartynas if (*--s1 == decimalpoint[i]) {
217aad11945Smartynas s1 -= i;
2187b36286aSmartynas continue;
219aad11945Smartynas }
220aad11945Smartynas #else
221aad11945Smartynas if (*--s1 == '.')
222aad11945Smartynas continue;
223aad11945Smartynas #endif
2241a653cbcSmartynas if (n == ULbits) {
2257b36286aSmartynas *x++ = L;
2267b36286aSmartynas L = 0;
2277b36286aSmartynas n = 0;
2287b36286aSmartynas }
2297b36286aSmartynas L |= (hexdig[*s1] & 0x0f) << n;
2307b36286aSmartynas n += 4;
2317b36286aSmartynas }
2327b36286aSmartynas *x++ = L;
2337b36286aSmartynas b->wds = n = x - b->x;
2341a653cbcSmartynas n = ULbits*n - hi0bits(L);
2357b36286aSmartynas nbits = fpi->nbits;
2367b36286aSmartynas lostbits = 0;
2377b36286aSmartynas x = b->x;
2387b36286aSmartynas if (n > nbits) {
2397b36286aSmartynas n -= nbits;
2407b36286aSmartynas if (any_on(b,n)) {
2417b36286aSmartynas lostbits = 1;
2427b36286aSmartynas k = n - 1;
2437b36286aSmartynas if (x[k>>kshift] & 1 << (k & kmask)) {
2447b36286aSmartynas lostbits = 2;
245aad11945Smartynas if (k > 0 && any_on(b,k))
2467b36286aSmartynas lostbits = 3;
2477b36286aSmartynas }
2487b36286aSmartynas }
2497b36286aSmartynas rshift(b, n);
2507b36286aSmartynas e += n;
2517b36286aSmartynas }
2527b36286aSmartynas else if (n < nbits) {
2537b36286aSmartynas n = nbits - n;
2547b36286aSmartynas b = lshift(b, n);
255384cfdc1Smartynas if (b == NULL)
256384cfdc1Smartynas return (STRTOG_NoMemory);
2577b36286aSmartynas e -= n;
2587b36286aSmartynas x = b->x;
2597b36286aSmartynas }
2607b36286aSmartynas if (e > fpi->emax) {
2617b36286aSmartynas ovfl:
2627b36286aSmartynas Bfree(b);
263aad11945Smartynas ovfl1:
264aad11945Smartynas #ifndef NO_ERRNO
265aad11945Smartynas errno = ERANGE;
266aad11945Smartynas #endif
2677b36286aSmartynas return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
2687b36286aSmartynas }
2697b36286aSmartynas irv = STRTOG_Normal;
2707b36286aSmartynas if (e < fpi->emin) {
2717b36286aSmartynas irv = STRTOG_Denormal;
2727b36286aSmartynas n = fpi->emin - e;
2737b36286aSmartynas if (n >= nbits) {
2747b36286aSmartynas switch (fpi->rounding) {
2757b36286aSmartynas case FPI_Round_near:
2767b36286aSmartynas if (n == nbits && (n < 2 || any_on(b,n-1)))
2777b36286aSmartynas goto one_bit;
2787b36286aSmartynas break;
2797b36286aSmartynas case FPI_Round_up:
2807b36286aSmartynas if (!sign)
2817b36286aSmartynas goto one_bit;
2827b36286aSmartynas break;
2837b36286aSmartynas case FPI_Round_down:
2847b36286aSmartynas if (sign) {
2857b36286aSmartynas one_bit:
2867b36286aSmartynas x[0] = b->wds = 1;
287aad11945Smartynas dret:
2887b36286aSmartynas *bp = b;
289aad11945Smartynas *exp = fpi->emin;
290aad11945Smartynas #ifndef NO_ERRNO
291aad11945Smartynas errno = ERANGE;
292aad11945Smartynas #endif
2937b36286aSmartynas return STRTOG_Denormal | STRTOG_Inexhi
2947b36286aSmartynas | STRTOG_Underflow;
2957b36286aSmartynas }
2967b36286aSmartynas }
2977b36286aSmartynas Bfree(b);
298aad11945Smartynas retz:
299aad11945Smartynas #ifndef NO_ERRNO
300aad11945Smartynas errno = ERANGE;
301aad11945Smartynas #endif
3027b36286aSmartynas return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
3037b36286aSmartynas }
3047b36286aSmartynas k = n - 1;
3057b36286aSmartynas if (lostbits)
3067b36286aSmartynas lostbits = 1;
3077b36286aSmartynas else if (k > 0)
3087b36286aSmartynas lostbits = any_on(b,k);
3097b36286aSmartynas if (x[k>>kshift] & 1 << (k & kmask))
3107b36286aSmartynas lostbits |= 2;
3117b36286aSmartynas nbits -= n;
3127b36286aSmartynas rshift(b,n);
3137b36286aSmartynas e = fpi->emin;
3147b36286aSmartynas }
3157b36286aSmartynas if (lostbits) {
3167b36286aSmartynas up = 0;
3177b36286aSmartynas switch(fpi->rounding) {
3187b36286aSmartynas case FPI_Round_zero:
3197b36286aSmartynas break;
3207b36286aSmartynas case FPI_Round_near:
3217b36286aSmartynas if (lostbits & 2
3221a653cbcSmartynas && (lostbits | x[0]) & 1)
3237b36286aSmartynas up = 1;
3247b36286aSmartynas break;
3257b36286aSmartynas case FPI_Round_up:
3267b36286aSmartynas up = 1 - sign;
3277b36286aSmartynas break;
3287b36286aSmartynas case FPI_Round_down:
3297b36286aSmartynas up = sign;
3307b36286aSmartynas }
3317b36286aSmartynas if (up) {
3327b36286aSmartynas k = b->wds;
3337b36286aSmartynas b = increment(b);
334384cfdc1Smartynas if (b == NULL)
335384cfdc1Smartynas return (STRTOG_NoMemory);
3367b36286aSmartynas x = b->x;
3377b36286aSmartynas if (irv == STRTOG_Denormal) {
3387b36286aSmartynas if (nbits == fpi->nbits - 1
3397b36286aSmartynas && x[nbits >> kshift] & 1 << (nbits & kmask))
3407b36286aSmartynas irv = STRTOG_Normal;
3417b36286aSmartynas }
3427b36286aSmartynas else if (b->wds > k
3431a653cbcSmartynas || ((n = nbits & kmask) !=0
3441a653cbcSmartynas && hi0bits(x[k-1]) < 32-n)) {
3457b36286aSmartynas rshift(b,1);
3467b36286aSmartynas if (++e > fpi->emax)
3477b36286aSmartynas goto ovfl;
3487b36286aSmartynas }
3497b36286aSmartynas irv |= STRTOG_Inexhi;
3507b36286aSmartynas }
3517b36286aSmartynas else
3527b36286aSmartynas irv |= STRTOG_Inexlo;
3537b36286aSmartynas }
3547b36286aSmartynas *bp = b;
3557b36286aSmartynas *exp = e;
3567b36286aSmartynas return irv;
3577b36286aSmartynas }
358