1/* Print floating point number in hexadecimal notation according to ISO C99.
2 Copyright (C) 1997-2024 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 <assert.h>
21#include <ctype.h>
22#include <ieee754.h>
23#include <math.h>
24#include <printf.h>
25#include <libioP.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <wchar.h>
30#include <_itoa.h>
31#include <_itowa.h>
32#include <locale/localeinfo.h>
33#include <stdbool.h>
34#include <rounding-mode.h>
35#include <sys/param.h>
36#include <printf_buffer.h>
37#include <errno.h>
38
39#if __HAVE_DISTINCT_FLOAT128
40# include "ieee754_float128.h"
41# include <ldbl-128/printf_fphex_macros.h>
42# define PRINT_FPHEX_FLOAT128 \
43 PRINT_FPHEX (_Float128, fpnum.flt128, ieee854_float128, \
44 IEEE854_FLOAT128_BIAS)
45#endif
46
47static void
48__printf_fphex_buffer (struct __printf_buffer *buf,
49 const char *decimal,
50 const struct printf_info *info,
51 const void *const *args)
52{
53 /* The floating-point value to output. */
54 union
55 {
56 union ieee754_double dbl;
57 long double ldbl;
58#if __HAVE_DISTINCT_FLOAT128
59 _Float128 flt128;
60#endif
61 }
62 fpnum;
63
64 /* This function always uses LC_NUMERIC. */
65 assert (info->extra == 0);
66
67 /* "NaN" or "Inf" for the special cases. */
68 const char *special = NULL;
69
70 /* Buffer for the generated number string for the mantissa. The
71 maximal size for the mantissa is 128 bits. */
72 char numbuf[32];
73 char *numstr;
74 char *numend;
75 int negative;
76
77 /* The maximal exponent of two in decimal notation has 5 digits. */
78 char expbuf[5];
79 char *expstr;
80 int expnegative;
81 int exponent;
82
83 /* Non-zero is mantissa is zero. */
84 int zero_mantissa;
85
86 /* The leading digit before the decimal point. */
87 char leading;
88
89 /* Precision. */
90 int precision = info->prec;
91
92 /* Width. */
93 int width = info->width;
94
95#define PRINTF_FPHEX_FETCH(FLOAT, VAR) \
96 { \
97 (VAR) = *(const FLOAT *) args[0]; \
98 \
99 /* Check for special values: not a number or infinity. */ \
100 if (isnan (VAR)) \
101 { \
102 if (isupper (info->spec)) \
103 special = "NAN"; \
104 else \
105 special = "nan"; \
106 } \
107 else \
108 { \
109 if (isinf (VAR)) \
110 { \
111 if (isupper (info->spec)) \
112 special = "INF"; \
113 else \
114 special = "inf"; \
115 } \
116 } \
117 negative = signbit (VAR); \
118 }
119
120 /* Fetch the argument value. */
121#if __HAVE_DISTINCT_FLOAT128
122 if (info->is_binary128)
123 PRINTF_FPHEX_FETCH (_Float128, fpnum.flt128)
124 else
125#endif
126#ifndef __NO_LONG_DOUBLE_MATH
127 if (info->is_long_double && sizeof (long double) > sizeof (double))
128 PRINTF_FPHEX_FETCH (long double, fpnum.ldbl)
129 else
130#endif
131 PRINTF_FPHEX_FETCH (double, fpnum.dbl.d)
132
133#undef PRINTF_FPHEX_FETCH
134
135 if (special)
136 {
137 int width = info->width;
138
139 if (negative || info->showsign || info->space)
140 --width;
141 width -= 3;
142
143 if (!info->left)
144 __printf_buffer_pad (buf, ch: ' ', count: width);
145
146 if (negative)
147 __printf_buffer_putc (buf, ch: '-');
148 else if (info->showsign)
149 __printf_buffer_putc (buf, ch: '+');
150 else if (info->space)
151 __printf_buffer_putc (buf, ch: ' ');
152
153 __printf_buffer_puts (buf, s: special);
154
155 if (info->left)
156 __printf_buffer_pad (buf, ch: ' ', count: width);
157
158 return;
159 }
160
161#if __HAVE_DISTINCT_FLOAT128
162 if (info->is_binary128)
163 PRINT_FPHEX_FLOAT128;
164 else
165#endif
166 if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
167 {
168 /* We have 52 bits of mantissa plus one implicit digit. Since
169 52 bits are representable without rest using hexadecimal
170 digits we use only the implicit digits for the number before
171 the decimal point. */
172 unsigned long long int num;
173
174 num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
175 | fpnum.dbl.ieee.mantissa1);
176
177 zero_mantissa = num == 0;
178
179 if (sizeof (unsigned long int) > 6)
180 numstr = _itoa_word (value: num, buflim: numbuf + sizeof numbuf, base: 16,
181 upper_case: info->spec == 'A');
182 else
183 numstr = _itoa (num, numbuf + sizeof numbuf, 16,
184 info->spec == 'A');
185
186 /* Fill with zeroes. */
187 while (numstr > numbuf + (sizeof numbuf - 13))
188 *--numstr = '0';
189
190 leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
191
192 exponent = fpnum.dbl.ieee.exponent;
193
194 if (exponent == 0)
195 {
196 if (zero_mantissa)
197 expnegative = 0;
198 else
199 {
200 /* This is a denormalized number. */
201 expnegative = 1;
202 exponent = IEEE754_DOUBLE_BIAS - 1;
203 }
204 }
205 else if (exponent >= IEEE754_DOUBLE_BIAS)
206 {
207 expnegative = 0;
208 exponent -= IEEE754_DOUBLE_BIAS;
209 }
210 else
211 {
212 expnegative = 1;
213 exponent = -(exponent - IEEE754_DOUBLE_BIAS);
214 }
215 }
216#ifdef PRINT_FPHEX_LONG_DOUBLE
217 else
218 PRINT_FPHEX_LONG_DOUBLE;
219#endif
220
221 /* Look for trailing zeroes. */
222 if (! zero_mantissa)
223 {
224 numend = array_end (numbuf);
225 while (numend[-1] == '0')
226 --numend;
227
228 bool do_round_away = false;
229
230 if (precision != -1 && precision < numend - numstr)
231 {
232 char last_digit = precision > 0 ? numstr[precision - 1] : leading;
233 char next_digit = numstr[precision];
234 int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
235 ? last_digit - 'A' + 10
236 : (last_digit >= 'a' && last_digit <= 'f'
237 ? last_digit - 'a' + 10
238 : last_digit - '0'));
239 int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
240 ? next_digit - 'A' + 10
241 : (next_digit >= 'a' && next_digit <= 'f'
242 ? next_digit - 'a' + 10
243 : next_digit - '0'));
244 bool more_bits = ((next_digit_value & 7) != 0
245 || precision + 1 < numend - numstr);
246 int rounding_mode = get_rounding_mode ();
247 do_round_away = round_away (negative, last_digit_odd: last_digit_value & 1,
248 half_bit: next_digit_value >= 8, more_bits,
249 mode: rounding_mode);
250 }
251
252 if (precision == -1)
253 precision = numend - numstr;
254 else if (do_round_away)
255 {
256 /* Round up. */
257 int cnt = precision;
258 while (--cnt >= 0)
259 {
260 char ch = numstr[cnt];
261 /* We assume that the digits and the letters are ordered
262 like in ASCII. This is true for the rest of GNU, too. */
263 if (ch == '9')
264 {
265 numstr[cnt] = info->spec; /* This is tricky,
266 think about it! */
267 break;
268 }
269 else if (tolower (ch) < 'f')
270 {
271 ++numstr[cnt];
272 break;
273 }
274 else
275 numstr[cnt] = '0';
276 }
277 if (cnt < 0)
278 {
279 /* The mantissa so far was fff...f Now increment the
280 leading digit. Here it is again possible that we
281 get an overflow. */
282 if (leading == '9')
283 leading = info->spec;
284 else if (tolower (leading) < 'f')
285 ++leading;
286 else
287 {
288 leading = '1';
289 if (expnegative)
290 {
291 exponent -= 4;
292 if (exponent <= 0)
293 {
294 exponent = -exponent;
295 expnegative = 0;
296 }
297 }
298 else
299 exponent += 4;
300 }
301 }
302 }
303 }
304 else
305 {
306 if (precision == -1)
307 precision = 0;
308 numend = numstr;
309 }
310
311 /* Now we can compute the exponent string. */
312 expstr = _itoa_word (value: exponent, buflim: expbuf + sizeof expbuf, base: 10, upper_case: 0);
313
314 /* Now we have all information to compute the size. */
315 width -= ((negative || info->showsign || info->space)
316 /* Sign. */
317 + 2 + 1 + 0 + precision + 1 + 1
318 /* 0x h . hhh P ExpoSign. */
319 + ((expbuf + sizeof expbuf) - expstr));
320 /* Exponent. */
321
322 /* Count the decimal point.
323 A special case when the mantissa or the precision is zero and the `#'
324 is not given. In this case we must not print the decimal point. */
325 if (precision > 0 || info->alt)
326 --width;
327
328 if (!info->left && info->pad != '0')
329 __printf_buffer_pad (buf, ch: ' ', count: width);
330
331 if (negative)
332 __printf_buffer_putc (buf, ch: '-');
333 else if (info->showsign)
334 __printf_buffer_putc (buf, ch: '+');
335 else if (info->space)
336 __printf_buffer_putc (buf, ch: ' ');
337
338 __printf_buffer_putc (buf, ch: '0');
339 if ('X' - 'A' == 'x' - 'a')
340 __printf_buffer_putc (buf, ch: info->spec + ('x' - 'a'));
341 else
342 __printf_buffer_putc (buf, ch: info->spec == 'A' ? 'X' : 'x');
343
344 if (!info->left && info->pad == '0')
345 __printf_buffer_pad (buf, ch: '0', count: width);
346
347 __printf_buffer_putc (buf, ch: leading);
348
349 if (precision > 0 || info->alt)
350 __printf_buffer_puts (buf, s: decimal);
351
352 if (precision > 0)
353 {
354 ssize_t tofill = precision - (numend - numstr);
355 __printf_buffer_write (buf, s: numstr, MIN (numend - numstr, precision));
356 __printf_buffer_pad (buf, ch: '0', count: tofill);
357 }
358
359 if ('P' - 'A' == 'p' - 'a')
360 __printf_buffer_putc (buf, ch: info->spec + ('p' - 'a'));
361 else
362 __printf_buffer_putc (buf, ch: info->spec == 'A' ? 'P' : 'p');
363
364 __printf_buffer_putc (buf, ch: expnegative ? '-' : '+');
365
366 __printf_buffer_write (buf, s: expstr, count: (expbuf + sizeof expbuf) - expstr);
367
368 if (info->left && info->pad != '0')
369 __printf_buffer_pad (buf, ch: info->pad, count: width);
370}
371
372void
373__printf_fphex_l_buffer (struct __printf_buffer *buf, locale_t loc,
374 const struct printf_info *info,
375 const void *const *args)
376{
377 __printf_fphex_buffer (buf, decimal: _nl_lookup (l: loc, LC_NUMERIC, DECIMAL_POINT),
378 info, args);
379}
380
381
382/* The wide buffer version is implemented by translating the output of
383 the multibyte version. */
384
385struct __printf_buffer_fphex_to_wide
386{
387 struct __printf_buffer base;
388 wchar_t decimalwc;
389 struct __wprintf_buffer *next;
390 char untranslated[PRINTF_BUFFER_SIZE_DIGITS];
391};
392
393/* Translate to wide characters, rewriting "." to the actual decimal
394 point. */
395void
396__printf_buffer_flush_fphex_to_wide (struct __printf_buffer_fphex_to_wide *buf)
397{
398 /* No need to adjust buf->base.written, only buf->next->written matters. */
399 for (char *p = buf->untranslated; p < buf->base.write_ptr; ++p)
400 {
401 /* wchar_t overlaps with char in the ASCII range. */
402 wchar_t ch = *p;
403 if (ch == L'.')
404 ch = buf->decimalwc;
405 __wprintf_buffer_putc (buf: buf->next, ch);
406 }
407
408 if (!__wprintf_buffer_has_failed (buf: buf->next))
409 buf->base.write_ptr = buf->untranslated;
410 else
411 __printf_buffer_mark_failed (buf: &buf->base);
412}
413
414void
415__wprintf_fphex_l_buffer (struct __wprintf_buffer *next, locale_t loc,
416 const struct printf_info *info,
417 const void *const *args)
418{
419 struct __printf_buffer_fphex_to_wide buf;
420 __printf_buffer_init (buf: &buf.base, base: buf.untranslated, len: sizeof (buf.untranslated),
421 mode: __printf_buffer_mode_fphex_to_wide);
422 buf.decimalwc = _nl_lookup_word (l: loc, LC_NUMERIC,
423 item: _NL_NUMERIC_DECIMAL_POINT_WC);
424 buf.next = next;
425 __printf_fphex_buffer (buf: &buf.base, decimal: ".", info, args);
426 if (__printf_buffer_has_failed (buf: &buf.base))
427 {
428 __wprintf_buffer_mark_failed (buf: buf.next);
429 return;
430 }
431 __printf_buffer_flush_fphex_to_wide (buf: &buf);
432}
433

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