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