Mercurial > hg > CbC > CbC_gcc
comparison libquadmath/printf/printf_fphex.c @ 68:561a7518be6b
update gcc-4.6
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 21 Aug 2011 07:07:55 +0900 |
parents | |
children | 04ced10e8804 |
comparison
equal
deleted
inserted
replaced
67:f6334be47118 | 68:561a7518be6b |
---|---|
1 /* Print floating point number in hexadecimal notation according to ISO C99. | |
2 Copyright (C) 1997-2002,2004,2006 Free Software Foundation, Inc. | |
3 This file is part of the GNU C Library. | |
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. | |
5 | |
6 The GNU C Library is free software; you can redistribute it and/or | |
7 modify it under the terms of the GNU Lesser General Public | |
8 License as published by the Free Software Foundation; either | |
9 version 2.1 of the License, or (at your option) any later version. | |
10 | |
11 The GNU C Library is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 Lesser General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU Lesser General Public | |
17 License along with the GNU C Library; if not, write to the Free | |
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 02111-1307 USA. */ | |
20 | |
21 #include <config.h> | |
22 #include <math.h> | |
23 #include <stdlib.h> | |
24 #include <stdio.h> | |
25 #include <string.h> | |
26 #define NDEBUG | |
27 #include <assert.h> | |
28 #include "quadmath-printf.h" | |
29 #include "_itoa.h" | |
30 #include "_itowa.h" | |
31 | |
32 | |
33 /* Macros for doing the actual output. */ | |
34 | |
35 #define outchar(ch) \ | |
36 do \ | |
37 { \ | |
38 register const int outc = (ch); \ | |
39 if (PUTC (outc, fp) == EOF) \ | |
40 return -1; \ | |
41 ++done; \ | |
42 } while (0) | |
43 | |
44 #define PRINT(ptr, wptr, len) \ | |
45 do \ | |
46 { \ | |
47 register size_t outlen = (len); \ | |
48 if (wide) \ | |
49 while (outlen-- > 0) \ | |
50 outchar (*wptr++); \ | |
51 else \ | |
52 while (outlen-- > 0) \ | |
53 outchar (*ptr++); \ | |
54 } while (0) | |
55 | |
56 #define PADN(ch, len) \ | |
57 do \ | |
58 { \ | |
59 if (PAD (fp, ch, len) != len) \ | |
60 return -1; \ | |
61 done += len; \ | |
62 } \ | |
63 while (0) | |
64 | |
65 | |
66 | |
67 int | |
68 __quadmath_printf_fphex (struct __quadmath_printf_file *fp, | |
69 const struct printf_info *info, | |
70 const void *const *args) | |
71 { | |
72 /* The floating-point value to output. */ | |
73 ieee854_float128 fpnum; | |
74 | |
75 /* Locale-dependent representation of decimal point. */ | |
76 const char *decimal; | |
77 wchar_t decimalwc; | |
78 | |
79 /* "NaN" or "Inf" for the special cases. */ | |
80 const char *special = NULL; | |
81 const wchar_t *wspecial = NULL; | |
82 | |
83 /* Buffer for the generated number string for the mantissa. The | |
84 maximal size for the mantissa is 128 bits. */ | |
85 char numbuf[32]; | |
86 char *numstr; | |
87 char *numend; | |
88 wchar_t wnumbuf[32]; | |
89 wchar_t *wnumstr; | |
90 wchar_t *wnumend; | |
91 int negative; | |
92 | |
93 /* The maximal exponent of two in decimal notation has 5 digits. */ | |
94 char expbuf[5]; | |
95 char *expstr; | |
96 wchar_t wexpbuf[5]; | |
97 wchar_t *wexpstr; | |
98 int expnegative; | |
99 int exponent; | |
100 | |
101 /* Non-zero is mantissa is zero. */ | |
102 int zero_mantissa; | |
103 | |
104 /* The leading digit before the decimal point. */ | |
105 char leading; | |
106 | |
107 /* Precision. */ | |
108 int precision = info->prec; | |
109 | |
110 /* Width. */ | |
111 int width = info->width; | |
112 | |
113 /* Number of characters written. */ | |
114 int done = 0; | |
115 | |
116 /* Nonzero if this is output on a wide character stream. */ | |
117 int wide = info->wide; | |
118 | |
119 /* Figure out the decimal point character. */ | |
120 #ifdef USE_NL_LANGINFO | |
121 if (info->extra == 0) | |
122 decimal = nl_langinfo (DECIMAL_POINT); | |
123 else | |
124 { | |
125 decimal = nl_langinfo (MON_DECIMAL_POINT); | |
126 if (*decimal == '\0') | |
127 decimal = nl_langinfo (DECIMAL_POINT); | |
128 } | |
129 /* The decimal point character must never be zero. */ | |
130 assert (*decimal != '\0'); | |
131 #elif defined USE_LOCALECONV | |
132 const struct lconv *lc = localeconv (); | |
133 if (info->extra == 0) | |
134 decimal = lc->decimal_point; | |
135 else | |
136 { | |
137 decimal = lc->mon_decimal_point; | |
138 if (decimal == NULL || *decimal == '\0') | |
139 decimal = lc->decimal_point; | |
140 } | |
141 if (decimal == NULL || *decimal == '\0') | |
142 decimal = "."; | |
143 #else | |
144 decimal = "."; | |
145 #endif | |
146 #ifdef USE_NL_LANGINFO_WC | |
147 if (info->extra == 0) | |
148 decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC); | |
149 else | |
150 { | |
151 decimalwc = nl_langinfo_wc (_NL_MONETARY_DECIMAL_POINT_WC); | |
152 if (decimalwc == L_('\0')) | |
153 decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC); | |
154 } | |
155 /* The decimal point character must never be zero. */ | |
156 assert (decimalwc != L_('\0')); | |
157 #else | |
158 decimalwc = L_('.'); | |
159 #endif | |
160 | |
161 /* Fetch the argument value. */ | |
162 { | |
163 fpnum.value = **(const __float128 **) args[0]; | |
164 | |
165 /* Check for special values: not a number or infinity. */ | |
166 if (isnanq (fpnum.value)) | |
167 { | |
168 negative = fpnum.ieee.negative != 0; | |
169 if (isupper (info->spec)) | |
170 { | |
171 special = "NAN"; | |
172 wspecial = L_("NAN"); | |
173 } | |
174 else | |
175 { | |
176 special = "nan"; | |
177 wspecial = L_("nan"); | |
178 } | |
179 } | |
180 else | |
181 { | |
182 if (isinfq (fpnum.value)) | |
183 { | |
184 if (isupper (info->spec)) | |
185 { | |
186 special = "INF"; | |
187 wspecial = L_("INF"); | |
188 } | |
189 else | |
190 { | |
191 special = "inf"; | |
192 wspecial = L_("inf"); | |
193 } | |
194 } | |
195 | |
196 negative = signbitq (fpnum.value); | |
197 } | |
198 } | |
199 | |
200 if (special) | |
201 { | |
202 int width = info->width; | |
203 | |
204 if (negative || info->showsign || info->space) | |
205 --width; | |
206 width -= 3; | |
207 | |
208 if (!info->left && width > 0) | |
209 PADN (' ', width); | |
210 | |
211 if (negative) | |
212 outchar ('-'); | |
213 else if (info->showsign) | |
214 outchar ('+'); | |
215 else if (info->space) | |
216 outchar (' '); | |
217 | |
218 PRINT (special, wspecial, 3); | |
219 | |
220 if (info->left && width > 0) | |
221 PADN (' ', width); | |
222 | |
223 return done; | |
224 } | |
225 | |
226 { | |
227 /* We have 112 bits of mantissa plus one implicit digit. Since | |
228 112 bits are representable without rest using hexadecimal | |
229 digits we use only the implicit digits for the number before | |
230 the decimal point. */ | |
231 uint64_t num0, num1; | |
232 | |
233 assert (sizeof (long double) == 16); | |
234 | |
235 num0 = fpnum.ieee.mant_high; | |
236 num1 = fpnum.ieee.mant_low; | |
237 | |
238 zero_mantissa = (num0|num1) == 0; | |
239 | |
240 if (sizeof (unsigned long int) > 6) | |
241 { | |
242 numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16, | |
243 info->spec == 'A'); | |
244 wnumstr = _itowa_word (num1, | |
245 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), | |
246 16, info->spec == 'A'); | |
247 } | |
248 else | |
249 { | |
250 numstr = _itoa (num1, numbuf + sizeof numbuf, 16, | |
251 info->spec == 'A'); | |
252 wnumstr = _itowa (num1, | |
253 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), | |
254 16, info->spec == 'A'); | |
255 } | |
256 | |
257 while (numstr > numbuf + (sizeof numbuf - 64 / 4)) | |
258 { | |
259 *--numstr = '0'; | |
260 *--wnumstr = L_('0'); | |
261 } | |
262 | |
263 if (sizeof (unsigned long int) > 6) | |
264 { | |
265 numstr = _itoa_word (num0, numstr, 16, info->spec == 'A'); | |
266 wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A'); | |
267 } | |
268 else | |
269 { | |
270 numstr = _itoa (num0, numstr, 16, info->spec == 'A'); | |
271 wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A'); | |
272 } | |
273 | |
274 /* Fill with zeroes. */ | |
275 while (numstr > numbuf + (sizeof numbuf - 112 / 4)) | |
276 { | |
277 *--numstr = '0'; | |
278 *--wnumstr = L_('0'); | |
279 } | |
280 | |
281 leading = fpnum.ieee.exponent == 0 ? '0' : '1'; | |
282 | |
283 exponent = fpnum.ieee.exponent; | |
284 | |
285 if (exponent == 0) | |
286 { | |
287 if (zero_mantissa) | |
288 expnegative = 0; | |
289 else | |
290 { | |
291 /* This is a denormalized number. */ | |
292 expnegative = 1; | |
293 exponent = IEEE854_FLOAT128_BIAS - 1; | |
294 } | |
295 } | |
296 else if (exponent >= IEEE854_FLOAT128_BIAS) | |
297 { | |
298 expnegative = 0; | |
299 exponent -= IEEE854_FLOAT128_BIAS; | |
300 } | |
301 else | |
302 { | |
303 expnegative = 1; | |
304 exponent = -(exponent - IEEE854_FLOAT128_BIAS); | |
305 } | |
306 } | |
307 | |
308 /* Look for trailing zeroes. */ | |
309 if (! zero_mantissa) | |
310 { | |
311 wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]]; | |
312 numend = &numbuf[sizeof numbuf / sizeof numbuf[0]]; | |
313 while (wnumend[-1] == L_('0')) | |
314 { | |
315 --wnumend; | |
316 --numend; | |
317 } | |
318 | |
319 if (precision == -1) | |
320 precision = numend - numstr; | |
321 else if (precision < numend - numstr | |
322 && (numstr[precision] > '8' | |
323 || (('A' < '0' || 'a' < '0') | |
324 && numstr[precision] < '0') | |
325 || (numstr[precision] == '8' | |
326 && (precision + 1 < numend - numstr | |
327 /* Round to even. */ | |
328 || (precision > 0 | |
329 && ((numstr[precision - 1] & 1) | |
330 ^ (isdigit (numstr[precision - 1]) == 0))) | |
331 || (precision == 0 | |
332 && ((leading & 1) | |
333 ^ (isdigit (leading) == 0))))))) | |
334 { | |
335 /* Round up. */ | |
336 int cnt = precision; | |
337 while (--cnt >= 0) | |
338 { | |
339 char ch = numstr[cnt]; | |
340 /* We assume that the digits and the letters are ordered | |
341 like in ASCII. This is true for the rest of GNU, too. */ | |
342 if (ch == '9') | |
343 { | |
344 wnumstr[cnt] = (wchar_t) info->spec; | |
345 numstr[cnt] = info->spec; /* This is tricky, | |
346 think about it! */ | |
347 break; | |
348 } | |
349 else if (tolower (ch) < 'f') | |
350 { | |
351 ++numstr[cnt]; | |
352 ++wnumstr[cnt]; | |
353 break; | |
354 } | |
355 else | |
356 { | |
357 numstr[cnt] = '0'; | |
358 wnumstr[cnt] = L_('0'); | |
359 } | |
360 } | |
361 if (cnt < 0) | |
362 { | |
363 /* The mantissa so far was fff...f Now increment the | |
364 leading digit. Here it is again possible that we | |
365 get an overflow. */ | |
366 if (leading == '9') | |
367 leading = info->spec; | |
368 else if (tolower (leading) < 'f') | |
369 ++leading; | |
370 else | |
371 { | |
372 leading = '1'; | |
373 if (expnegative) | |
374 { | |
375 exponent -= 4; | |
376 if (exponent <= 0) | |
377 { | |
378 exponent = -exponent; | |
379 expnegative = 0; | |
380 } | |
381 } | |
382 else | |
383 exponent += 4; | |
384 } | |
385 } | |
386 } | |
387 } | |
388 else | |
389 { | |
390 if (precision == -1) | |
391 precision = 0; | |
392 numend = numstr; | |
393 wnumend = wnumstr; | |
394 } | |
395 | |
396 /* Now we can compute the exponent string. */ | |
397 expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0); | |
398 wexpstr = _itowa_word (exponent, | |
399 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0); | |
400 | |
401 /* Now we have all information to compute the size. */ | |
402 width -= ((negative || info->showsign || info->space) | |
403 /* Sign. */ | |
404 + 2 + 1 + 0 + precision + 1 + 1 | |
405 /* 0x h . hhh P ExpoSign. */ | |
406 + ((expbuf + sizeof expbuf) - expstr)); | |
407 /* Exponent. */ | |
408 | |
409 /* Count the decimal point. | |
410 A special case when the mantissa or the precision is zero and the `#' | |
411 is not given. In this case we must not print the decimal point. */ | |
412 if (precision > 0 || info->alt) | |
413 width -= wide ? 1 : strlen (decimal); | |
414 | |
415 if (!info->left && info->pad != '0' && width > 0) | |
416 PADN (' ', width); | |
417 | |
418 if (negative) | |
419 outchar ('-'); | |
420 else if (info->showsign) | |
421 outchar ('+'); | |
422 else if (info->space) | |
423 outchar (' '); | |
424 | |
425 outchar ('0'); | |
426 if ('X' - 'A' == 'x' - 'a') | |
427 outchar (info->spec + ('x' - 'a')); | |
428 else | |
429 outchar (info->spec == 'A' ? 'X' : 'x'); | |
430 | |
431 if (!info->left && info->pad == '0' && width > 0) | |
432 PADN ('0', width); | |
433 | |
434 outchar (leading); | |
435 | |
436 if (precision > 0 || info->alt) | |
437 { | |
438 const wchar_t *wtmp = &decimalwc; | |
439 PRINT (decimal, wtmp, wide ? 1 : strlen (decimal)); | |
440 } | |
441 | |
442 if (precision > 0) | |
443 { | |
444 ssize_t tofill = precision - (numend - numstr); | |
445 PRINT (numstr, wnumstr, MIN (numend - numstr, precision)); | |
446 if (tofill > 0) | |
447 PADN ('0', tofill); | |
448 } | |
449 | |
450 if ('P' - 'A' == 'p' - 'a') | |
451 outchar (info->spec + ('p' - 'a')); | |
452 else | |
453 outchar (info->spec == 'A' ? 'P' : 'p'); | |
454 | |
455 outchar (expnegative ? '-' : '+'); | |
456 | |
457 PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr); | |
458 | |
459 if (info->left && info->pad != '0' && width > 0) | |
460 PADN (info->pad, width); | |
461 | |
462 return done; | |
463 } |