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

source code of glibc/stdio-common/printf_fphex.c