printf_fphex.c revision 1.1.1.1 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 fpnum.value = **(const __float128 **) args[0];
169
170 /* Check for special values: not a number or infinity. */
171 if (isnanq (fpnum.value))
172 {
173 negative = fpnum.ieee.negative != 0;
174 if (isupper (info->spec))
175 {
176 special = "NAN";
177 wspecial = L_("NAN");
178 }
179 else
180 {
181 special = "nan";
182 wspecial = L_("nan");
183 }
184 }
185 else
186 {
187 if (isinfq (fpnum.value))
188 {
189 if (isupper (info->spec))
190 {
191 special = "INF";
192 wspecial = L_("INF");
193 }
194 else
195 {
196 special = "inf";
197 wspecial = L_("inf");
198 }
199 }
200
201 negative = signbitq (fpnum.value);
202 }
203 }
204
205 if (special)
206 {
207 int width = info->width;
208
209 if (negative || info->showsign || info->space)
210 --width;
211 width -= 3;
212
213 if (!info->left && width > 0)
214 PADN (' ', width);
215
216 if (negative)
217 outchar ('-');
218 else if (info->showsign)
219 outchar ('+');
220 else if (info->space)
221 outchar (' ');
222
223 PRINT (special, wspecial, 3);
224
225 if (info->left && width > 0)
226 PADN (' ', width);
227
228 return done;
229 }
230
231 {
232 /* We have 112 bits of mantissa plus one implicit digit. Since
233 112 bits are representable without rest using hexadecimal
234 digits we use only the implicit digits for the number before
235 the decimal point. */
236 uint64_t num0, num1;
237
238 assert (sizeof (long double) == 16);
239
240 num0 = (((unsigned long long int) fpnum.ieee.mantissa0) << 32
241 | fpnum.ieee.mantissa1);
242 num1 = (((unsigned long long int) fpnum.ieee.mantissa2) << 32
243 | fpnum.ieee.mantissa3);
244
245 zero_mantissa = (num0|num1) == 0;
246
247 if (sizeof (unsigned long int) > 6)
248 {
249 numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16,
250 info->spec == 'A');
251 wnumstr = _itowa_word (num1,
252 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
253 16, info->spec == 'A');
254 }
255 else
256 {
257 numstr = _itoa (num1, numbuf + sizeof numbuf, 16,
258 info->spec == 'A');
259 wnumstr = _itowa (num1,
260 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
261 16, info->spec == 'A');
262 }
263
264 while (numstr > numbuf + (sizeof numbuf - 64 / 4))
265 {
266 *--numstr = '0';
267 *--wnumstr = L_('0');
268 }
269
270 if (sizeof (unsigned long int) > 6)
271 {
272 numstr = _itoa_word (num0, numstr, 16, info->spec == 'A');
273 wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A');
274 }
275 else
276 {
277 numstr = _itoa (num0, numstr, 16, info->spec == 'A');
278 wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A');
279 }
280
281 /* Fill with zeroes. */
282 while (numstr > numbuf + (sizeof numbuf - 112 / 4))
283 {
284 *--wnumstr = L_('0');
285 *--numstr = '0';
286 }
287
288 leading = fpnum.ieee.exponent == 0 ? '0' : '1';
289
290 exponent = fpnum.ieee.exponent;
291
292 if (exponent == 0)
293 {
294 if (zero_mantissa)
295 expnegative = 0;
296 else
297 {
298 /* This is a denormalized number. */
299 expnegative = 1;
300 exponent = IEEE854_FLOAT128_BIAS - 1;
301 }
302 }
303 else if (exponent >= IEEE854_FLOAT128_BIAS)
304 {
305 expnegative = 0;
306 exponent -= IEEE854_FLOAT128_BIAS;
307 }
308 else
309 {
310 expnegative = 1;
311 exponent = -(exponent - IEEE854_FLOAT128_BIAS);
312 }
313 }
314
315 /* Look for trailing zeroes. */
316 if (! zero_mantissa)
317 {
318 wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
319 numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
320 while (wnumend[-1] == L_('0'))
321 {
322 --wnumend;
323 --numend;
324 }
325
326 do_round_away = false;
327
328 if (precision != -1 && precision < numend - numstr)
329 {
330 char last_digit = precision > 0 ? numstr[precision - 1] : leading;
331 char next_digit = numstr[precision];
332 int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
333 ? last_digit - 'A' + 10
334 : (last_digit >= 'a' && last_digit <= 'f'
335 ? last_digit - 'a' + 10
336 : last_digit - '0'));
337 int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
338 ? next_digit - 'A' + 10
339 : (next_digit >= 'a' && next_digit <= 'f'
340 ? next_digit - 'a' + 10
341 : next_digit - '0'));
342 bool more_bits = ((next_digit_value & 7) != 0
343 || precision + 1 < numend - numstr);
344 #ifdef HAVE_FENV_H
345 int rounding_mode = get_rounding_mode ();
346 do_round_away = round_away (negative, last_digit_value & 1,
347 next_digit_value >= 8, more_bits,
348 rounding_mode);
349 #endif
350 }
351
352 if (precision == -1)
353 precision = numend - numstr;
354 else if (do_round_away)
355 {
356 /* Round up. */
357 int cnt = precision;
358 while (--cnt >= 0)
359 {
360 char ch = numstr[cnt];
361 /* We assume that the digits and the letters are ordered
362 like in ASCII. This is true for the rest of GNU, too. */
363 if (ch == '9')
364 {
365 wnumstr[cnt] = (wchar_t) info->spec;
366 numstr[cnt] = info->spec; /* This is tricky,
367 think about it! */
368 break;
369 }
370 else if (tolower (ch) < 'f')
371 {
372 ++numstr[cnt];
373 ++wnumstr[cnt];
374 break;
375 }
376 else
377 {
378 numstr[cnt] = '0';
379 wnumstr[cnt] = L_('0');
380 }
381 }
382 if (cnt < 0)
383 {
384 /* The mantissa so far was fff...f Now increment the
385 leading digit. Here it is again possible that we
386 get an overflow. */
387 if (leading == '9')
388 leading = info->spec;
389 else if (tolower (leading) < 'f')
390 ++leading;
391 else
392 {
393 leading = '1';
394 if (expnegative)
395 {
396 exponent -= 4;
397 if (exponent <= 0)
398 {
399 exponent = -exponent;
400 expnegative = 0;
401 }
402 }
403 else
404 exponent += 4;
405 }
406 }
407 }
408 }
409 else
410 {
411 if (precision == -1)
412 precision = 0;
413 numend = numstr;
414 wnumend = wnumstr;
415 }
416
417 /* Now we can compute the exponent string. */
418 expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
419 wexpstr = _itowa_word (exponent,
420 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
421
422 /* Now we have all information to compute the size. */
423 width -= ((negative || info->showsign || info->space)
424 /* Sign. */
425 + 2 + 1 + 0 + precision + 1 + 1
426 /* 0x h . hhh P ExpoSign. */
427 + ((expbuf + sizeof expbuf) - expstr));
428 /* Exponent. */
429
430 /* Count the decimal point.
431 A special case when the mantissa or the precision is zero and the `#'
432 is not given. In this case we must not print the decimal point. */
433 if (precision > 0 || info->alt)
434 width -= wide ? 1 : strlen (decimal);
435
436 if (!info->left && info->pad != '0' && width > 0)
437 PADN (' ', width);
438
439 if (negative)
440 outchar ('-');
441 else if (info->showsign)
442 outchar ('+');
443 else if (info->space)
444 outchar (' ');
445
446 outchar ('0');
447 if ('X' - 'A' == 'x' - 'a')
448 outchar (info->spec + ('x' - 'a'));
449 else
450 outchar (info->spec == 'A' ? 'X' : 'x');
451
452 if (!info->left && info->pad == '0' && width > 0)
453 PADN ('0', width);
454
455 outchar (leading);
456
457 if (precision > 0 || info->alt)
458 {
459 const wchar_t *wtmp = &decimalwc;
460 PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
461 }
462
463 if (precision > 0)
464 {
465 ssize_t tofill = precision - (numend - numstr);
466 PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
467 if (tofill > 0)
468 PADN ('0', tofill);
469 }
470
471 if ('P' - 'A' == 'p' - 'a')
472 outchar (info->spec + ('p' - 'a'));
473 else
474 outchar (info->spec == 'A' ? 'P' : 'p');
475
476 outchar (expnegative ? '-' : '+');
477
478 PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
479
480 if (info->left && info->pad != '0' && width > 0)
481 PADN (info->pad, width);
482
483 return done;
484 }
485