gethex.c revision 182709
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 big, esign, havedig, irv, j, k, n, n0, 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 *bp = 0; 60 havedig = 0; 61 s0 = *(CONST unsigned char **)sp + 2; 62 while(s0[havedig] == '0') 63 havedig++; 64 s0 += havedig; 65 s = s0; 66 decpt = 0; 67 zret = 0; 68 e = 0; 69 if (!hexdig[*s]) { 70 zret = 1; 71 if (*s != decimalpoint) 72 goto pcheck; 73 decpt = ++s; 74 if (!hexdig[*s]) 75 goto pcheck; 76 while(*s == '0') 77 s++; 78 if (hexdig[*s]) 79 zret = 0; 80 havedig = 1; 81 s0 = s; 82 } 83 while(hexdig[*s]) 84 s++; 85 if (*s == decimalpoint && !decpt) { 86 decpt = ++s; 87 while(hexdig[*s]) 88 s++; 89 } 90 if (decpt) 91 e = -(((Long)(s-decpt)) << 2); 92 pcheck: 93 s1 = s; 94 big = esign = 0; 95 switch(*s) { 96 case 'p': 97 case 'P': 98 switch(*++s) { 99 case '-': 100 esign = 1; 101 /* no break */ 102 case '+': 103 s++; 104 } 105 if ((n = hexdig[*s]) == 0 || n > 0x19) { 106 s = s1; 107 break; 108 } 109 e1 = n - 0x10; 110 while((n = hexdig[*++s]) !=0 && n <= 0x19) { 111 if (e1 & 0xf8000000) 112 big = 1; 113 e1 = 10*e1 + n - 0x10; 114 } 115 if (esign) 116 e1 = -e1; 117 e += e1; 118 } 119 *sp = (char*)s; 120 if (!havedig) 121 *sp = s0 - 1; 122 if (zret) 123 return STRTOG_Zero; 124 if (big) { 125 if (esign) { 126 switch(fpi->rounding) { 127 case FPI_Round_up: 128 if (sign) 129 break; 130 goto ret_tiny; 131 case FPI_Round_down: 132 if (!sign) 133 break; 134 goto ret_tiny; 135 } 136 goto retz; 137 ret_tiny: 138 b = Balloc(0); 139 b->wds = 1; 140 b->x[0] = 1; 141 goto dret; 142 } 143 switch(fpi->rounding) { 144 case FPI_Round_near: 145 goto ovfl1; 146 case FPI_Round_up: 147 if (!sign) 148 goto ovfl1; 149 goto ret_big; 150 case FPI_Round_down: 151 if (sign) 152 goto ovfl1; 153 goto ret_big; 154 } 155 ret_big: 156 nbits = fpi->nbits; 157 n0 = n = nbits >> kshift; 158 if (nbits & kmask) 159 ++n; 160 for(j = n, k = 0; j >>= 1; ++k); 161 *bp = b = Balloc(k); 162 b->wds = n; 163 for(j = 0; j < n0; ++j) 164 b->x[j] = ALL_ON; 165 if (n > n0) 166 b->x[j] = ULbits >> (ULbits - (nbits & kmask)); 167 *exp = fpi->emin; 168 return STRTOG_Normal | STRTOG_Inexlo; 169 } 170 n = s1 - s0 - 1; 171 for(k = 0; n > 7; n >>= 1) 172 k++; 173 b = Balloc(k); 174 x = b->x; 175 n = 0; 176 L = 0; 177 while(s1 > s0) { 178 if (*--s1 == decimalpoint) 179 continue; 180 if (n == 32) { 181 *x++ = L; 182 L = 0; 183 n = 0; 184 } 185 L |= (hexdig[*s1] & 0x0f) << n; 186 n += 4; 187 } 188 *x++ = L; 189 b->wds = n = x - b->x; 190 n = 32*n - hi0bits(L); 191 nbits = fpi->nbits; 192 lostbits = 0; 193 x = b->x; 194 if (n > nbits) { 195 n -= nbits; 196 if (any_on(b,n)) { 197 lostbits = 1; 198 k = n - 1; 199 if (x[k>>kshift] & 1 << (k & kmask)) { 200 lostbits = 2; 201 if (k > 0 && any_on(b,k)) 202 lostbits = 3; 203 } 204 } 205 rshift(b, n); 206 e += n; 207 } 208 else if (n < nbits) { 209 n = nbits - n; 210 b = lshift(b, n); 211 e -= n; 212 x = b->x; 213 } 214 if (e > fpi->emax) { 215 ovfl: 216 Bfree(b); 217 ovfl1: 218#ifndef NO_ERRNO 219 errno = ERANGE; 220#endif 221 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 222 } 223 irv = STRTOG_Normal; 224 if (e < fpi->emin) { 225 irv = STRTOG_Denormal; 226 n = fpi->emin - e; 227 if (n >= nbits) { 228 switch (fpi->rounding) { 229 case FPI_Round_near: 230 if (n == nbits && (n < 2 || any_on(b,n-1))) 231 goto one_bit; 232 break; 233 case FPI_Round_up: 234 if (!sign) 235 goto one_bit; 236 break; 237 case FPI_Round_down: 238 if (sign) { 239 one_bit: 240 x[0] = b->wds = 1; 241 dret: 242 *bp = b; 243 *exp = fpi->emin; 244#ifndef NO_ERRNO 245 errno = ERANGE; 246#endif 247 return STRTOG_Denormal | STRTOG_Inexhi 248 | STRTOG_Underflow; 249 } 250 } 251 Bfree(b); 252 retz: 253#ifndef NO_ERRNO 254 errno = ERANGE; 255#endif 256 return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 257 } 258 k = n - 1; 259 if (lostbits) 260 lostbits = 1; 261 else if (k > 0) 262 lostbits = any_on(b,k); 263 if (x[k>>kshift] & 1 << (k & kmask)) 264 lostbits |= 2; 265 nbits -= n; 266 rshift(b,n); 267 e = fpi->emin; 268 } 269 if (lostbits) { 270 up = 0; 271 switch(fpi->rounding) { 272 case FPI_Round_zero: 273 break; 274 case FPI_Round_near: 275 if (lostbits & 2 276 && (lostbits & 1) | x[0] & 1) 277 up = 1; 278 break; 279 case FPI_Round_up: 280 up = 1 - sign; 281 break; 282 case FPI_Round_down: 283 up = sign; 284 } 285 if (up) { 286 k = b->wds; 287 b = increment(b); 288 x = b->x; 289 if (irv == STRTOG_Denormal) { 290 if (nbits == fpi->nbits - 1 291 && x[nbits >> kshift] & 1 << (nbits & kmask)) 292 irv = STRTOG_Normal; 293 } 294 else if (b->wds > k 295 || (n = nbits & kmask) !=0 296 && hi0bits(x[k-1]) < 32-n) { 297 rshift(b,1); 298 if (++e > fpi->emax) 299 goto ovfl; 300 } 301 irv |= STRTOG_Inexhi; 302 } 303 else 304 irv |= STRTOG_Inexlo; 305 } 306 *bp = b; 307 *exp = e; 308 return irv; 309 } 310