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.
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.
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.
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/>. */
19 #include <array_length.h>
32 #include <locale/localeinfo.h>
34 #include <rounding-mode.h>
35 #include <sys/param.h>
36 #include <printf_buffer.h>
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)
48 __printf_fphex_buffer (struct __printf_buffer
*buf
,
50 const struct printf_info
*info
,
51 const void *const *args
)
53 /* The floating-point value to output. */
56 union ieee754_double dbl
;
58 #if __HAVE_DISTINCT_FLOAT128
64 /* This function always uses LC_NUMERIC. */
65 assert (info
->extra
== 0);
67 /* "NaN" or "Inf" for the special cases. */
68 const char *special
= NULL
;
70 /* Buffer for the generated number string for the mantissa. The
71 maximal size for the mantissa is 128 bits. */
77 /* The maximal exponent of two in decimal notation has 5 digits. */
83 /* Non-zero is mantissa is zero. */
86 /* The leading digit before the decimal point. */
90 int precision
= info
->prec
;
93 int width
= info
->width
;
95 #define PRINTF_FPHEX_FETCH(FLOAT, VAR) \
97 (VAR) = *(const FLOAT *) args[0]; \
99 /* Check for special values: not a number or infinity. */ \
102 if (isupper (info->spec)) \
111 if (isupper (info->spec)) \
117 negative = signbit (VAR); \
120 /* Fetch the argument value. */
121 #if __HAVE_DISTINCT_FLOAT128
122 if (info
->is_binary128
)
123 PRINTF_FPHEX_FETCH (_Float128
, fpnum
.flt128
)
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
)
131 PRINTF_FPHEX_FETCH (double, fpnum
.dbl
.d
)
133 #undef PRINTF_FPHEX_FETCH
137 int width
= info
->width
;
139 if (negative
|| info
->showsign
|| info
->space
)
144 __printf_buffer_pad (buf
, ' ', width
);
147 __printf_buffer_putc (buf
, '-');
148 else if (info
->showsign
)
149 __printf_buffer_putc (buf
, '+');
150 else if (info
->space
)
151 __printf_buffer_putc (buf
, ' ');
153 __printf_buffer_puts (buf
, special
);
156 __printf_buffer_pad (buf
, ' ', width
);
161 #if __HAVE_DISTINCT_FLOAT128
162 if (info
->is_binary128
)
163 PRINT_FPHEX_FLOAT128
;
166 if (info
->is_long_double
== 0 || sizeof (double) == sizeof (long double))
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
;
174 num
= (((unsigned long long int) fpnum
.dbl
.ieee
.mantissa0
) << 32
175 | fpnum
.dbl
.ieee
.mantissa1
);
177 zero_mantissa
= num
== 0;
179 if (sizeof (unsigned long int) > 6)
180 numstr
= _itoa_word (num
, numbuf
+ sizeof numbuf
, 16,
183 numstr
= _itoa (num
, numbuf
+ sizeof numbuf
, 16,
186 /* Fill with zeroes. */
187 while (numstr
> numbuf
+ (sizeof numbuf
- 13))
190 leading
= fpnum
.dbl
.ieee
.exponent
== 0 ? '0' : '1';
192 exponent
= fpnum
.dbl
.ieee
.exponent
;
200 /* This is a denormalized number. */
202 exponent
= IEEE754_DOUBLE_BIAS
- 1;
205 else if (exponent
>= IEEE754_DOUBLE_BIAS
)
208 exponent
-= IEEE754_DOUBLE_BIAS
;
213 exponent
= -(exponent
- IEEE754_DOUBLE_BIAS
);
216 #ifdef PRINT_FPHEX_LONG_DOUBLE
218 PRINT_FPHEX_LONG_DOUBLE
;
221 /* Look for trailing zeroes. */
224 numend
= array_end (numbuf
);
225 while (numend
[-1] == '0')
228 bool do_round_away
= false;
230 if (precision
!= -1 && precision
< numend
- numstr
)
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_value
& 1,
248 next_digit_value
>= 8, more_bits
,
253 precision
= numend
- numstr
;
254 else if (do_round_away
)
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. */
265 numstr
[cnt
] = info
->spec
; /* This is tricky,
269 else if (tolower (ch
) < 'f')
279 /* The mantissa so far was fff...f Now increment the
280 leading digit. Here it is again possible that we
283 leading
= info
->spec
;
284 else if (tolower (leading
) < 'f')
294 exponent
= -exponent
;
311 /* Now we can compute the exponent string. */
312 expstr
= _itoa_word (exponent
, expbuf
+ sizeof expbuf
, 10, 0);
314 /* Now we have all information to compute the size. */
315 width
-= ((negative
|| info
->showsign
|| info
->space
)
317 + 2 + 1 + 0 + precision
+ 1 + 1
318 /* 0x h . hhh P ExpoSign. */
319 + ((expbuf
+ sizeof expbuf
) - expstr
));
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
)
328 if (!info
->left
&& info
->pad
!= '0')
329 __printf_buffer_pad (buf
, ' ', width
);
332 __printf_buffer_putc (buf
, '-');
333 else if (info
->showsign
)
334 __printf_buffer_putc (buf
, '+');
335 else if (info
->space
)
336 __printf_buffer_putc (buf
, ' ');
338 __printf_buffer_putc (buf
, '0');
339 if ('X' - 'A' == 'x' - 'a')
340 __printf_buffer_putc (buf
, info
->spec
+ ('x' - 'a'));
342 __printf_buffer_putc (buf
, info
->spec
== 'A' ? 'X' : 'x');
344 if (!info
->left
&& info
->pad
== '0')
345 __printf_buffer_pad (buf
, '0', width
);
347 __printf_buffer_putc (buf
, leading
);
349 if (precision
> 0 || info
->alt
)
350 __printf_buffer_puts (buf
, decimal
);
354 ssize_t tofill
= precision
- (numend
- numstr
);
355 __printf_buffer_write (buf
, numstr
, MIN (numend
- numstr
, precision
));
356 __printf_buffer_pad (buf
, '0', tofill
);
359 if ('P' - 'A' == 'p' - 'a')
360 __printf_buffer_putc (buf
, info
->spec
+ ('p' - 'a'));
362 __printf_buffer_putc (buf
, info
->spec
== 'A' ? 'P' : 'p');
364 __printf_buffer_putc (buf
, expnegative
? '-' : '+');
366 __printf_buffer_write (buf
, expstr
, (expbuf
+ sizeof expbuf
) - expstr
);
368 if (info
->left
&& info
->pad
!= '0')
369 __printf_buffer_pad (buf
, info
->pad
, width
);
373 __printf_fphex_l_buffer (struct __printf_buffer
*buf
, locale_t loc
,
374 const struct printf_info
*info
,
375 const void *const *args
)
377 __printf_fphex_buffer (buf
, _nl_lookup (loc
, LC_NUMERIC
, DECIMAL_POINT
),
382 /* The wide buffer version is implemented by translating the output of
383 the multibyte version. */
385 struct __printf_buffer_fphex_to_wide
387 struct __printf_buffer base
;
389 struct __wprintf_buffer
*next
;
390 char untranslated
[PRINTF_BUFFER_SIZE_DIGITS
];
393 /* Translate to wide characters, rewriting "." to the actual decimal
396 __printf_buffer_flush_fphex_to_wide (struct __printf_buffer_fphex_to_wide
*buf
)
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
)
401 /* wchar_t overlaps with char in the ASCII range. */
405 __wprintf_buffer_putc (buf
->next
, ch
);
408 if (!__wprintf_buffer_has_failed (buf
->next
))
409 buf
->base
.write_ptr
= buf
->untranslated
;
411 __printf_buffer_mark_failed (&buf
->base
);
415 __wprintf_fphex_l_buffer (struct __wprintf_buffer
*next
, locale_t loc
,
416 const struct printf_info
*info
,
417 const void *const *args
)
419 struct __printf_buffer_fphex_to_wide buf
;
420 __printf_buffer_init (&buf
.base
, buf
.untranslated
, sizeof (buf
.untranslated
),
421 __printf_buffer_mode_fphex_to_wide
);
422 buf
.decimalwc
= _nl_lookup_word (loc
, LC_NUMERIC
,
423 _NL_NUMERIC_DECIMAL_POINT_WC
);
425 __printf_fphex_buffer (&buf
.base
, ".", info
, args
);
426 if (__printf_buffer_has_failed (&buf
.base
))
428 __wprintf_buffer_mark_failed (buf
.next
);
431 __printf_buffer_flush_fphex_to_wide (&buf
);