1 | /**************************************************************** |
---|
2 | |
---|
3 | The author of this software is David M. Gay. |
---|
4 | |
---|
5 | Copyright (C) 1998 by Lucent Technologies |
---|
6 | All Rights Reserved |
---|
7 | |
---|
8 | Permission to use, copy, modify, and distribute this software and |
---|
9 | its documentation for any purpose and without fee is hereby |
---|
10 | granted, provided that the above copyright notice appear in all |
---|
11 | copies and that both that the copyright notice and this |
---|
12 | permission notice and warranty disclaimer appear in supporting |
---|
13 | documentation, and that the name of Lucent or any of its entities |
---|
14 | not be used in advertising or publicity pertaining to |
---|
15 | distribution of the software without specific, written prior |
---|
16 | permission. |
---|
17 | |
---|
18 | LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
---|
19 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. |
---|
20 | IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY |
---|
21 | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
22 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER |
---|
23 | IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
---|
24 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF |
---|
25 | THIS 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 <_ansi.h> |
---|
33 | #include <reent.h> |
---|
34 | #include <string.h> |
---|
35 | #include <locale.h> |
---|
36 | #include "mprec.h" |
---|
37 | #include "gdtoa.h" |
---|
38 | #include "gd_qnan.h" |
---|
39 | |
---|
40 | #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && !defined(_SMALL_HEXDIG) |
---|
41 | const unsigned char __hexdig[256]= |
---|
42 | { |
---|
43 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
44 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
45 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
46 | 16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0, |
---|
47 | 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, |
---|
48 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
49 | 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, |
---|
50 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
51 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
52 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
53 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
54 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
55 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
56 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
57 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
---|
58 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 |
---|
59 | }; |
---|
60 | #else /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && !defined(_SMALL_HEXDIG) */ |
---|
61 | unsigned char |
---|
62 | __hexdig_fun (unsigned char c) |
---|
63 | { |
---|
64 | if(c>='0' && c<='9') return c-'0'+0x10; |
---|
65 | else if(c>='a' && c<='f') return c-'a'+0x10+10; |
---|
66 | else if(c>='A' && c<='F') return c-'A'+0x10+10; |
---|
67 | else return 0; |
---|
68 | } |
---|
69 | #endif /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && !defined(_SMALL_HEXDIG) */ |
---|
70 | |
---|
71 | static void |
---|
72 | rshift (_Bigint *b, |
---|
73 | int k) |
---|
74 | { |
---|
75 | __ULong *x, *x1, *xe, y; |
---|
76 | int n; |
---|
77 | |
---|
78 | x = x1 = b->_x; |
---|
79 | n = k >> kshift; |
---|
80 | if (n < b->_wds) { |
---|
81 | xe = x + b->_wds; |
---|
82 | x += n; |
---|
83 | if (k &= kmask) { |
---|
84 | n = ULbits - k; |
---|
85 | y = *x++ >> k; |
---|
86 | while(x < xe) { |
---|
87 | *x1++ = (y | (*x << n)) & ALL_ON; |
---|
88 | y = *x++ >> k; |
---|
89 | } |
---|
90 | if ((*x1 = y) !=0) |
---|
91 | x1++; |
---|
92 | } |
---|
93 | else |
---|
94 | while(x < xe) |
---|
95 | *x1++ = *x++; |
---|
96 | } |
---|
97 | if ((b->_wds = x1 - b->_x) == 0) |
---|
98 | b->_x[0] = 0; |
---|
99 | } |
---|
100 | |
---|
101 | static _Bigint * |
---|
102 | increment (struct _reent *ptr, |
---|
103 | _Bigint *b) |
---|
104 | { |
---|
105 | __ULong *x, *xe; |
---|
106 | _Bigint *b1; |
---|
107 | #ifdef Pack_16 |
---|
108 | __ULong carry = 1, y; |
---|
109 | #endif |
---|
110 | |
---|
111 | x = b->_x; |
---|
112 | xe = x + b->_wds; |
---|
113 | #ifdef Pack_32 |
---|
114 | do { |
---|
115 | if (*x < (__ULong)0xffffffffL) { |
---|
116 | ++*x; |
---|
117 | return b; |
---|
118 | } |
---|
119 | *x++ = 0; |
---|
120 | } while(x < xe); |
---|
121 | #else |
---|
122 | do { |
---|
123 | y = *x + carry; |
---|
124 | carry = y >> 16; |
---|
125 | *x++ = y & 0xffff; |
---|
126 | if (!carry) |
---|
127 | return b; |
---|
128 | } while(x < xe); |
---|
129 | if (carry) |
---|
130 | #endif |
---|
131 | { |
---|
132 | if (b->_wds >= b->_maxwds) { |
---|
133 | b1 = Balloc(ptr, b->_k+1); |
---|
134 | Bcopy(b1, b); |
---|
135 | Bfree(ptr, b); |
---|
136 | b = b1; |
---|
137 | } |
---|
138 | b->_x[b->_wds++] = 1; |
---|
139 | } |
---|
140 | return b; |
---|
141 | } |
---|
142 | |
---|
143 | |
---|
144 | int |
---|
145 | gethex (struct _reent *ptr, const char **sp, const FPI *fpi, |
---|
146 | Long *exp, _Bigint **bp, int sign, locale_t loc) |
---|
147 | { |
---|
148 | _Bigint *b; |
---|
149 | const unsigned char *decpt, *s0, *s, *s1; |
---|
150 | int esign, havedig, irv, k, n, nbits, up, zret; |
---|
151 | __ULong L, lostbits, *x; |
---|
152 | Long e, e1; |
---|
153 | unsigned char *decimalpoint = (unsigned char *) |
---|
154 | __localeconv_l (loc)->decimal_point; |
---|
155 | size_t decp_len = strlen ((const char *) decimalpoint); |
---|
156 | unsigned char decp_end = decimalpoint[decp_len - 1]; |
---|
157 | |
---|
158 | havedig = 0; |
---|
159 | s0 = *(const unsigned char **)sp + 2; |
---|
160 | while(s0[havedig] == '0') |
---|
161 | havedig++; |
---|
162 | s0 += havedig; |
---|
163 | s = s0; |
---|
164 | decpt = 0; |
---|
165 | zret = 0; |
---|
166 | e = 0; |
---|
167 | if (!__get_hexdig(*s)) { |
---|
168 | zret = 1; |
---|
169 | if (strncmp ((const char *) s, (const char *) decimalpoint, |
---|
170 | decp_len) != 0) |
---|
171 | goto pcheck; |
---|
172 | decpt = (s += decp_len); |
---|
173 | if (!__get_hexdig(*s)) |
---|
174 | goto pcheck; |
---|
175 | while(*s == '0') |
---|
176 | s++; |
---|
177 | if (__get_hexdig(*s)) |
---|
178 | zret = 0; |
---|
179 | havedig = 1; |
---|
180 | s0 = s; |
---|
181 | } |
---|
182 | while(__get_hexdig(*s)) |
---|
183 | s++; |
---|
184 | if (strncmp ((const char *) s, (const char *) decimalpoint, |
---|
185 | decp_len) == 0 |
---|
186 | && !decpt) { |
---|
187 | decpt = (s += decp_len); |
---|
188 | while(__get_hexdig(*s)) |
---|
189 | s++; |
---|
190 | } |
---|
191 | if (decpt) |
---|
192 | e = -(((Long)(s-decpt)) << 2); |
---|
193 | pcheck: |
---|
194 | s1 = s; |
---|
195 | switch(*s) { |
---|
196 | case 'p': |
---|
197 | case 'P': |
---|
198 | esign = 0; |
---|
199 | switch(*++s) { |
---|
200 | case '-': |
---|
201 | esign = 1; |
---|
202 | /* no break */ |
---|
203 | case '+': |
---|
204 | s++; |
---|
205 | } |
---|
206 | if ((n = __get_hexdig(*s)) == 0 || n > 0x19) { |
---|
207 | s = s1; |
---|
208 | break; |
---|
209 | } |
---|
210 | e1 = n - 0x10; |
---|
211 | while((n = __get_hexdig(*++s)) !=0 && n <= 0x19) |
---|
212 | e1 = 10*e1 + n - 0x10; |
---|
213 | if (esign) |
---|
214 | e1 = -e1; |
---|
215 | e += e1; |
---|
216 | } |
---|
217 | *sp = (char*)s; |
---|
218 | if (zret) |
---|
219 | return havedig ? STRTOG_Zero : STRTOG_NoNumber; |
---|
220 | n = s1 - s0 - 1; |
---|
221 | for(k = 0; n > 7; n >>= 1) |
---|
222 | k++; |
---|
223 | b = Balloc(ptr, k); |
---|
224 | x = b->_x; |
---|
225 | n = 0; |
---|
226 | L = 0; |
---|
227 | while(s1 > s0) { |
---|
228 | if (*--s1 == decp_end && s1 - decp_len + 1 >= s0 |
---|
229 | && strncmp ((const char *) s1 - decp_len + 1, |
---|
230 | (const char *) decimalpoint, decp_len) == 0) { |
---|
231 | s1 -= decp_len - 1; /* Note the --s1 above! */ |
---|
232 | continue; |
---|
233 | } |
---|
234 | if (n == 32) { |
---|
235 | *x++ = L; |
---|
236 | L = 0; |
---|
237 | n = 0; |
---|
238 | } |
---|
239 | L |= (__get_hexdig(*s1) & 0x0f) << n; |
---|
240 | n += 4; |
---|
241 | } |
---|
242 | *x++ = L; |
---|
243 | b->_wds = n = x - b->_x; |
---|
244 | n = 32*n - hi0bits(L); |
---|
245 | nbits = fpi->nbits; |
---|
246 | lostbits = 0; |
---|
247 | x = b->_x; |
---|
248 | if (n > nbits) { |
---|
249 | n -= nbits; |
---|
250 | if (any_on(b,n)) { |
---|
251 | lostbits = 1; |
---|
252 | k = n - 1; |
---|
253 | if (x[k>>kshift] & 1 << (k & kmask)) { |
---|
254 | lostbits = 2; |
---|
255 | if (k > 1 && any_on(b,k-1)) |
---|
256 | lostbits = 3; |
---|
257 | } |
---|
258 | } |
---|
259 | rshift(b, n); |
---|
260 | e += n; |
---|
261 | } |
---|
262 | else if (n < nbits) { |
---|
263 | n = nbits - n; |
---|
264 | b = lshift(ptr, b, n); |
---|
265 | e -= n; |
---|
266 | x = b->_x; |
---|
267 | } |
---|
268 | if (e > fpi->emax) { |
---|
269 | ovfl: |
---|
270 | Bfree(ptr, b); |
---|
271 | *bp = 0; |
---|
272 | return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; |
---|
273 | } |
---|
274 | irv = STRTOG_Normal; |
---|
275 | if (e < fpi->emin) { |
---|
276 | irv = STRTOG_Denormal; |
---|
277 | n = fpi->emin - e; |
---|
278 | if (n >= nbits) { |
---|
279 | switch (fpi->rounding) { |
---|
280 | case FPI_Round_near: |
---|
281 | if (n == nbits && (n < 2 || any_on(b,n-1))) |
---|
282 | goto one_bit; |
---|
283 | break; |
---|
284 | case FPI_Round_up: |
---|
285 | if (!sign) |
---|
286 | goto one_bit; |
---|
287 | break; |
---|
288 | case FPI_Round_down: |
---|
289 | if (sign) { |
---|
290 | one_bit: |
---|
291 | *exp = fpi->emin; |
---|
292 | x[0] = b->_wds = 1; |
---|
293 | *bp = b; |
---|
294 | return STRTOG_Denormal | STRTOG_Inexhi |
---|
295 | | STRTOG_Underflow; |
---|
296 | } |
---|
297 | } |
---|
298 | Bfree(ptr, b); |
---|
299 | *bp = 0; |
---|
300 | return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; |
---|
301 | } |
---|
302 | k = n - 1; |
---|
303 | if (lostbits) |
---|
304 | lostbits = 1; |
---|
305 | else if (k > 0) |
---|
306 | lostbits = any_on(b,k); |
---|
307 | if (x[k>>kshift] & 1 << (k & kmask)) |
---|
308 | lostbits |= 2; |
---|
309 | nbits -= n; |
---|
310 | rshift(b,n); |
---|
311 | e = fpi->emin; |
---|
312 | } |
---|
313 | if (lostbits) { |
---|
314 | up = 0; |
---|
315 | switch(fpi->rounding) { |
---|
316 | case FPI_Round_zero: |
---|
317 | break; |
---|
318 | case FPI_Round_near: |
---|
319 | if ((lostbits & 2) |
---|
320 | && ((lostbits & 1) | (x[0] & 1))) |
---|
321 | up = 1; |
---|
322 | break; |
---|
323 | case FPI_Round_up: |
---|
324 | up = 1 - sign; |
---|
325 | break; |
---|
326 | case FPI_Round_down: |
---|
327 | up = sign; |
---|
328 | } |
---|
329 | if (up) { |
---|
330 | k = b->_wds; |
---|
331 | b = increment(ptr, b); |
---|
332 | x = b->_x; |
---|
333 | if (irv == STRTOG_Denormal) { |
---|
334 | if (nbits == fpi->nbits - 1 |
---|
335 | && x[nbits >> kshift] & 1 << (nbits & kmask)) |
---|
336 | irv = STRTOG_Normal; |
---|
337 | } |
---|
338 | else if ((b->_wds > k) |
---|
339 | || ((n = nbits & kmask) !=0 |
---|
340 | && (hi0bits(x[k-1]) < 32-n))) { |
---|
341 | rshift(b,1); |
---|
342 | if (++e > fpi->emax) |
---|
343 | goto ovfl; |
---|
344 | } |
---|
345 | irv |= STRTOG_Inexhi; |
---|
346 | } |
---|
347 | else |
---|
348 | irv |= STRTOG_Inexlo; |
---|
349 | } |
---|
350 | *bp = b; |
---|
351 | *exp = e; |
---|
352 | return irv; |
---|
353 | } |
---|
354 | |
---|