gethex.c revision 179918
1/**************************************************************** 2 3The author of this software is David M. Gay. 4 5Copyright (C) 1998 by Lucent Technologies 6All Rights Reserved 7 8Permission to use, copy, modify, and distribute this software and 9its documentation for any purpose and without fee is hereby 10granted, provided that the above copyright notice appear in all 11copies and that both that the copyright notice and this 12permission notice and warranty disclaimer appear in supporting 13documentation, and that the name of Lucent or any of its entities 14not be used in advertising or publicity pertaining to 15distribution of the software without specific, written prior 16permission. 17 18LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 20IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 21SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 23IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 24ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 25THIS SOFTWARE. 26 27****************************************************************/ 28 29/* Please send bug reports to David M. Gay (dmg at acm dot org, 30 * with " at " changed at "@" and " dot " changed to "."). */ 31 32#include "gdtoaimp.h" 33 34#ifdef USE_LOCALE 35#include "locale.h" 36#endif 37 38 int 39#ifdef KR_headers 40gethex(sp, fpi, exp, bp, sign) 41 CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; 42#else 43gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) 44#endif 45{ 46 Bigint *b; 47 CONST unsigned char *decpt, *s0, *s, *s1; 48 int esign, havedig, irv, k, n, nbits, up, zret; 49 ULong L, lostbits, *x; 50 Long e, e1; 51#ifdef USE_LOCALE 52 unsigned char decimalpoint = *localeconv()->decimal_point; 53#else 54#define decimalpoint '.' 55#endif 56 57 if (!hexdig['0']) 58 hexdig_init_D2A(); 59 havedig = 0; 60 s0 = *(CONST unsigned char **)sp + 2; 61 while(s0[havedig] == '0') 62 havedig++; 63 s0 += havedig; 64 s = s0; 65 decpt = 0; 66 zret = 0; 67 e = 0; 68 if (!hexdig[*s]) { 69 zret = 1; 70 if (*s != decimalpoint) 71 goto pcheck; 72 decpt = ++s; 73 if (!hexdig[*s]) 74 goto pcheck; 75 while(*s == '0') 76 s++; 77 if (hexdig[*s]) 78 zret = 0; 79 havedig = 1; 80 s0 = s; 81 } 82 while(hexdig[*s]) 83 s++; 84 if (*s == decimalpoint && !decpt) { 85 decpt = ++s; 86 while(hexdig[*s]) 87 s++; 88 } 89 if (decpt) 90 e = -(((Long)(s-decpt)) << 2); 91 pcheck: 92 s1 = s; 93 switch(*s) { 94 case 'p': 95 case 'P': 96 esign = 0; 97 switch(*++s) { 98 case '-': 99 esign = 1; 100 /* no break */ 101 case '+': 102 s++; 103 } 104 if ((n = hexdig[*s]) == 0 || n > 0x19) { 105 s = s1; 106 break; 107 } 108 e1 = n - 0x10; 109 while((n = hexdig[*++s]) !=0 && n <= 0x19) 110 e1 = 10*e1 + n - 0x10; 111 if (esign) 112 e1 = -e1; 113 e += e1; 114 } 115 *sp = (char*)s; 116 if (zret) { 117 if (!havedig) 118 *sp = s0 - 1; 119 return STRTOG_Zero; 120 } 121 n = s1 - s0 - 1; 122 for(k = 0; n > 7; n >>= 1) 123 k++; 124 b = Balloc(k); 125 x = b->x; 126 n = 0; 127 L = 0; 128 while(s1 > s0) { 129 if (*--s1 == decimalpoint) 130 continue; 131 if (n == 32) { 132 *x++ = L; 133 L = 0; 134 n = 0; 135 } 136 L |= (hexdig[*s1] & 0x0f) << n; 137 n += 4; 138 } 139 *x++ = L; 140 b->wds = n = x - b->x; 141 n = 32*n - hi0bits(L); 142 nbits = fpi->nbits; 143 lostbits = 0; 144 x = b->x; 145 if (n > nbits) { 146 n -= nbits; 147 if (any_on(b,n)) { 148 lostbits = 1; 149 k = n - 1; 150 if (x[k>>kshift] & 1 << (k & kmask)) { 151 lostbits = 2; 152 if (k > 1 && any_on(b,k-1)) 153 lostbits = 3; 154 } 155 } 156 rshift(b, n); 157 e += n; 158 } 159 else if (n < nbits) { 160 n = nbits - n; 161 b = lshift(b, n); 162 e -= n; 163 x = b->x; 164 } 165 if (e > fpi->emax) { 166 ovfl: 167 Bfree(b); 168 *bp = 0; 169 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 170 } 171 irv = STRTOG_Normal; 172 if (e < fpi->emin) { 173 irv = STRTOG_Denormal; 174 n = fpi->emin - e; 175 if (n >= nbits) { 176 switch (fpi->rounding) { 177 case FPI_Round_near: 178 if (n == nbits && (n < 2 || any_on(b,n-1))) 179 goto one_bit; 180 break; 181 case FPI_Round_up: 182 if (!sign) 183 goto one_bit; 184 break; 185 case FPI_Round_down: 186 if (sign) { 187 one_bit: 188 *exp = fpi->emin; 189 x[0] = b->wds = 1; 190 *bp = b; 191 return STRTOG_Denormal | STRTOG_Inexhi 192 | STRTOG_Underflow; 193 } 194 } 195 Bfree(b); 196 *bp = 0; 197 return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 198 } 199 k = n - 1; 200 if (lostbits) 201 lostbits = 1; 202 else if (k > 0) 203 lostbits = any_on(b,k); 204 if (x[k>>kshift] & 1 << (k & kmask)) 205 lostbits |= 2; 206 nbits -= n; 207 rshift(b,n); 208 e = fpi->emin; 209 } 210 if (lostbits) { 211 up = 0; 212 switch(fpi->rounding) { 213 case FPI_Round_zero: 214 break; 215 case FPI_Round_near: 216 if (lostbits & 2 217 && (lostbits & 1) | x[0] & 1) 218 up = 1; 219 break; 220 case FPI_Round_up: 221 up = 1 - sign; 222 break; 223 case FPI_Round_down: 224 up = sign; 225 } 226 if (up) { 227 k = b->wds; 228 b = increment(b); 229 x = b->x; 230 if (irv == STRTOG_Denormal) { 231 if (nbits == fpi->nbits - 1 232 && x[nbits >> kshift] & 1 << (nbits & kmask)) 233 irv = STRTOG_Normal; 234 } 235 else if (b->wds > k 236 || (n = nbits & kmask) !=0 237 && hi0bits(x[k-1]) < 32-n) { 238 rshift(b,1); 239 if (++e > fpi->emax) 240 goto ovfl; 241 } 242 irv |= STRTOG_Inexhi; 243 } 244 else 245 irv |= STRTOG_Inexlo; 246 } 247 *bp = b; 248 *exp = e; 249 return irv; 250 } 251