gethex.c revision 182709
1112158Sdas/**************************************************************** 2112158Sdas 3112158SdasThe author of this software is David M. Gay. 4112158Sdas 5112158SdasCopyright (C) 1998 by Lucent Technologies 6112158SdasAll Rights Reserved 7112158Sdas 8112158SdasPermission to use, copy, modify, and distribute this software and 9112158Sdasits documentation for any purpose and without fee is hereby 10112158Sdasgranted, provided that the above copyright notice appear in all 11112158Sdascopies and that both that the copyright notice and this 12112158Sdaspermission notice and warranty disclaimer appear in supporting 13112158Sdasdocumentation, and that the name of Lucent or any of its entities 14112158Sdasnot be used in advertising or publicity pertaining to 15112158Sdasdistribution of the software without specific, written prior 16112158Sdaspermission. 17112158Sdas 18112158SdasLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19112158SdasINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 20112158SdasIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 21112158SdasSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22112158SdasWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 23112158SdasIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 24112158SdasARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 25112158SdasTHIS SOFTWARE. 26112158Sdas 27112158Sdas****************************************************************/ 28112158Sdas 29165743Sdas/* Please send bug reports to David M. Gay (dmg at acm dot org, 30165743Sdas * with " at " changed at "@" and " dot " changed to "."). */ 31112158Sdas 32112158Sdas#include "gdtoaimp.h" 33112158Sdas 34112620Sdas#ifdef USE_LOCALE 35112620Sdas#include "locale.h" 36112620Sdas#endif 37112620Sdas 38112158Sdas int 39112158Sdas#ifdef KR_headers 40112158Sdasgethex(sp, fpi, exp, bp, sign) 41112158Sdas CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; 42112158Sdas#else 43112158Sdasgethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) 44112158Sdas#endif 45112158Sdas{ 46112158Sdas Bigint *b; 47112158Sdas CONST unsigned char *decpt, *s0, *s, *s1; 48182709Sdas int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; 49112158Sdas ULong L, lostbits, *x; 50112158Sdas Long e, e1; 51112620Sdas#ifdef USE_LOCALE 52124703Sdas unsigned char decimalpoint = *localeconv()->decimal_point; 53112620Sdas#else 54112620Sdas#define decimalpoint '.' 55112620Sdas#endif 56112158Sdas 57112158Sdas if (!hexdig['0']) 58112158Sdas hexdig_init_D2A(); 59182709Sdas *bp = 0; 60112158Sdas havedig = 0; 61112158Sdas s0 = *(CONST unsigned char **)sp + 2; 62112158Sdas while(s0[havedig] == '0') 63112158Sdas havedig++; 64112158Sdas s0 += havedig; 65112158Sdas s = s0; 66112158Sdas decpt = 0; 67165743Sdas zret = 0; 68165743Sdas e = 0; 69112158Sdas if (!hexdig[*s]) { 70165743Sdas zret = 1; 71165743Sdas if (*s != decimalpoint) 72165743Sdas goto pcheck; 73165743Sdas decpt = ++s; 74165743Sdas if (!hexdig[*s]) 75165743Sdas goto pcheck; 76112158Sdas while(*s == '0') 77112158Sdas s++; 78165743Sdas if (hexdig[*s]) 79165743Sdas zret = 0; 80112158Sdas havedig = 1; 81112158Sdas s0 = s; 82112158Sdas } 83112158Sdas while(hexdig[*s]) 84112158Sdas s++; 85112620Sdas if (*s == decimalpoint && !decpt) { 86112158Sdas decpt = ++s; 87112158Sdas while(hexdig[*s]) 88112158Sdas s++; 89112158Sdas } 90112158Sdas if (decpt) 91112158Sdas e = -(((Long)(s-decpt)) << 2); 92165743Sdas pcheck: 93112158Sdas s1 = s; 94182709Sdas big = esign = 0; 95112158Sdas switch(*s) { 96112158Sdas case 'p': 97112158Sdas case 'P': 98112158Sdas switch(*++s) { 99112158Sdas case '-': 100112158Sdas esign = 1; 101112158Sdas /* no break */ 102112158Sdas case '+': 103112158Sdas s++; 104112158Sdas } 105112158Sdas if ((n = hexdig[*s]) == 0 || n > 0x19) { 106112158Sdas s = s1; 107112158Sdas break; 108112158Sdas } 109112158Sdas e1 = n - 0x10; 110182709Sdas while((n = hexdig[*++s]) !=0 && n <= 0x19) { 111182709Sdas if (e1 & 0xf8000000) 112182709Sdas big = 1; 113112158Sdas e1 = 10*e1 + n - 0x10; 114182709Sdas } 115112158Sdas if (esign) 116112158Sdas e1 = -e1; 117112158Sdas e += e1; 118112158Sdas } 119112158Sdas *sp = (char*)s; 120182709Sdas if (!havedig) 121182709Sdas *sp = s0 - 1; 122182709Sdas if (zret) 123179918Sdas return STRTOG_Zero; 124182709Sdas if (big) { 125182709Sdas if (esign) { 126182709Sdas switch(fpi->rounding) { 127182709Sdas case FPI_Round_up: 128182709Sdas if (sign) 129182709Sdas break; 130182709Sdas goto ret_tiny; 131182709Sdas case FPI_Round_down: 132182709Sdas if (!sign) 133182709Sdas break; 134182709Sdas goto ret_tiny; 135182709Sdas } 136182709Sdas goto retz; 137182709Sdas ret_tiny: 138182709Sdas b = Balloc(0); 139182709Sdas b->wds = 1; 140182709Sdas b->x[0] = 1; 141182709Sdas goto dret; 142182709Sdas } 143182709Sdas switch(fpi->rounding) { 144182709Sdas case FPI_Round_near: 145182709Sdas goto ovfl1; 146182709Sdas case FPI_Round_up: 147182709Sdas if (!sign) 148182709Sdas goto ovfl1; 149182709Sdas goto ret_big; 150182709Sdas case FPI_Round_down: 151182709Sdas if (sign) 152182709Sdas goto ovfl1; 153182709Sdas goto ret_big; 154182709Sdas } 155182709Sdas ret_big: 156182709Sdas nbits = fpi->nbits; 157182709Sdas n0 = n = nbits >> kshift; 158182709Sdas if (nbits & kmask) 159182709Sdas ++n; 160182709Sdas for(j = n, k = 0; j >>= 1; ++k); 161182709Sdas *bp = b = Balloc(k); 162182709Sdas b->wds = n; 163182709Sdas for(j = 0; j < n0; ++j) 164182709Sdas b->x[j] = ALL_ON; 165182709Sdas if (n > n0) 166182709Sdas b->x[j] = ULbits >> (ULbits - (nbits & kmask)); 167182709Sdas *exp = fpi->emin; 168182709Sdas return STRTOG_Normal | STRTOG_Inexlo; 169179918Sdas } 170112158Sdas n = s1 - s0 - 1; 171112158Sdas for(k = 0; n > 7; n >>= 1) 172112158Sdas k++; 173112158Sdas b = Balloc(k); 174112158Sdas x = b->x; 175112158Sdas n = 0; 176112158Sdas L = 0; 177112158Sdas while(s1 > s0) { 178112620Sdas if (*--s1 == decimalpoint) 179112158Sdas continue; 180112158Sdas if (n == 32) { 181112158Sdas *x++ = L; 182112158Sdas L = 0; 183112158Sdas n = 0; 184112158Sdas } 185112158Sdas L |= (hexdig[*s1] & 0x0f) << n; 186112158Sdas n += 4; 187112158Sdas } 188112158Sdas *x++ = L; 189112158Sdas b->wds = n = x - b->x; 190112158Sdas n = 32*n - hi0bits(L); 191112158Sdas nbits = fpi->nbits; 192112158Sdas lostbits = 0; 193112158Sdas x = b->x; 194112158Sdas if (n > nbits) { 195112158Sdas n -= nbits; 196112158Sdas if (any_on(b,n)) { 197112158Sdas lostbits = 1; 198112158Sdas k = n - 1; 199112158Sdas if (x[k>>kshift] & 1 << (k & kmask)) { 200112158Sdas lostbits = 2; 201182709Sdas if (k > 0 && any_on(b,k)) 202112158Sdas lostbits = 3; 203112158Sdas } 204112158Sdas } 205112158Sdas rshift(b, n); 206112158Sdas e += n; 207112158Sdas } 208112158Sdas else if (n < nbits) { 209112158Sdas n = nbits - n; 210112158Sdas b = lshift(b, n); 211112158Sdas e -= n; 212112158Sdas x = b->x; 213112158Sdas } 214112158Sdas if (e > fpi->emax) { 215112158Sdas ovfl: 216112158Sdas Bfree(b); 217182709Sdas ovfl1: 218182709Sdas#ifndef NO_ERRNO 219182709Sdas errno = ERANGE; 220182709Sdas#endif 221112158Sdas return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; 222112158Sdas } 223112158Sdas irv = STRTOG_Normal; 224112158Sdas if (e < fpi->emin) { 225112158Sdas irv = STRTOG_Denormal; 226112158Sdas n = fpi->emin - e; 227112158Sdas if (n >= nbits) { 228112158Sdas switch (fpi->rounding) { 229112158Sdas case FPI_Round_near: 230124703Sdas if (n == nbits && (n < 2 || any_on(b,n-1))) 231112158Sdas goto one_bit; 232112158Sdas break; 233112158Sdas case FPI_Round_up: 234112158Sdas if (!sign) 235112158Sdas goto one_bit; 236112158Sdas break; 237112158Sdas case FPI_Round_down: 238112158Sdas if (sign) { 239112158Sdas one_bit: 240112158Sdas x[0] = b->wds = 1; 241182709Sdas dret: 242112158Sdas *bp = b; 243182709Sdas *exp = fpi->emin; 244182709Sdas#ifndef NO_ERRNO 245182709Sdas errno = ERANGE; 246182709Sdas#endif 247112158Sdas return STRTOG_Denormal | STRTOG_Inexhi 248112158Sdas | STRTOG_Underflow; 249112158Sdas } 250112158Sdas } 251112158Sdas Bfree(b); 252182709Sdas retz: 253182709Sdas#ifndef NO_ERRNO 254182709Sdas errno = ERANGE; 255182709Sdas#endif 256112158Sdas return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; 257112158Sdas } 258112158Sdas k = n - 1; 259112158Sdas if (lostbits) 260112158Sdas lostbits = 1; 261112158Sdas else if (k > 0) 262112158Sdas lostbits = any_on(b,k); 263112158Sdas if (x[k>>kshift] & 1 << (k & kmask)) 264112158Sdas lostbits |= 2; 265112158Sdas nbits -= n; 266112158Sdas rshift(b,n); 267112158Sdas e = fpi->emin; 268112158Sdas } 269112158Sdas if (lostbits) { 270112158Sdas up = 0; 271112158Sdas switch(fpi->rounding) { 272112158Sdas case FPI_Round_zero: 273112158Sdas break; 274112158Sdas case FPI_Round_near: 275112158Sdas if (lostbits & 2 276112158Sdas && (lostbits & 1) | x[0] & 1) 277112158Sdas up = 1; 278112158Sdas break; 279112158Sdas case FPI_Round_up: 280112158Sdas up = 1 - sign; 281112158Sdas break; 282112158Sdas case FPI_Round_down: 283112158Sdas up = sign; 284112158Sdas } 285112158Sdas if (up) { 286112158Sdas k = b->wds; 287112158Sdas b = increment(b); 288112158Sdas x = b->x; 289124703Sdas if (irv == STRTOG_Denormal) { 290124703Sdas if (nbits == fpi->nbits - 1 291124703Sdas && x[nbits >> kshift] & 1 << (nbits & kmask)) 292124703Sdas irv = STRTOG_Normal; 293124703Sdas } 294124703Sdas else if (b->wds > k 295112158Sdas || (n = nbits & kmask) !=0 296112158Sdas && hi0bits(x[k-1]) < 32-n) { 297112158Sdas rshift(b,1); 298112158Sdas if (++e > fpi->emax) 299112158Sdas goto ovfl; 300112158Sdas } 301112158Sdas irv |= STRTOG_Inexhi; 302112158Sdas } 303112158Sdas else 304112158Sdas irv |= STRTOG_Inexlo; 305112158Sdas } 306112158Sdas *bp = b; 307112158Sdas *exp = e; 308112158Sdas return irv; 309112158Sdas } 310