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.
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>
30 #include <locale/localeinfo.h>
32 #include <rounding-mode.h>
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)
42 /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */
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))
49 #define putc(c, f) (wide \
50 ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
53 /* Macros for doing the actual output. */
58 const int outc = (ch); \
59 if (putc (outc, fp) == EOF) \
64 #define PRINT(ptr, wptr, len) \
67 size_t outlen = (len); \
69 while (outlen-- > 0) \
72 while (outlen-- > 0) \
76 #define PADN(ch, len) \
79 if (PAD (fp, ch, len) != len) \
86 # define MIN(a,b) ((a)<(b)?(a):(b))
91 __printf_fphex (FILE *fp
,
92 const struct printf_info
*info
,
93 const void *const *args
)
95 /* The floating-point value to output. */
98 union ieee754_double dbl
;
100 #if __HAVE_DISTINCT_FLOAT128
106 /* This function always uses LC_NUMERIC. */
107 assert (info
->extra
== 0);
109 /* Locale-dependent representation of decimal point. Hexadecimal
110 formatting always using LC_NUMERIC (disregarding info->extra). */
111 const char *decimal
= _NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
);
112 wchar_t decimalwc
= _NL_CURRENT_WORD (LC_NUMERIC
,
113 _NL_NUMERIC_DECIMAL_POINT_WC
);
115 /* The decimal point character must never be zero. */
116 assert (*decimal
!= '\0' && decimalwc
!= L
'\0');
118 /* "NaN" or "Inf" for the special cases. */
119 const char *special
= NULL
;
120 const wchar_t *wspecial
= NULL
;
122 /* Buffer for the generated number string for the mantissa. The
123 maximal size for the mantissa is 128 bits. */
132 /* The maximal exponent of two in decimal notation has 5 digits. */
140 /* Non-zero is mantissa is zero. */
143 /* The leading digit before the decimal point. */
147 int precision
= info
->prec
;
150 int width
= info
->width
;
152 /* Number of characters written. */
155 /* Nonzero if this is output on a wide character stream. */
156 int wide
= info
->wide
;
158 #define PRINTF_FPHEX_FETCH(FLOAT, VAR) \
160 (VAR) = *(const FLOAT *) args[0]; \
162 /* Check for special values: not a number or infinity. */ \
165 if (isupper (info->spec)) \
180 if (isupper (info->spec)) \
192 negative = signbit (VAR); \
195 /* Fetch the argument value. */
196 #if __HAVE_DISTINCT_FLOAT128
197 if (info
->is_binary128
)
198 PRINTF_FPHEX_FETCH (_Float128
, fpnum
.flt128
)
201 #ifndef __NO_LONG_DOUBLE_MATH
202 if (info
->is_long_double
&& sizeof (long double) > sizeof (double))
203 PRINTF_FPHEX_FETCH (long double, fpnum
.ldbl
)
206 PRINTF_FPHEX_FETCH (double, fpnum
.dbl
.d
)
208 #undef PRINTF_FPHEX_FETCH
212 int width
= info
->width
;
214 if (negative
|| info
->showsign
|| info
->space
)
218 if (!info
->left
&& width
> 0)
223 else if (info
->showsign
)
225 else if (info
->space
)
228 PRINT (special
, wspecial
, 3);
230 if (info
->left
&& width
> 0)
236 #if __HAVE_DISTINCT_FLOAT128
237 if (info
->is_binary128
)
238 PRINT_FPHEX_FLOAT128
;
241 if (info
->is_long_double
== 0 || sizeof (double) == sizeof (long double))
243 /* We have 52 bits of mantissa plus one implicit digit. Since
244 52 bits are representable without rest using hexadecimal
245 digits we use only the implicit digits for the number before
246 the decimal point. */
247 unsigned long long int num
;
249 num
= (((unsigned long long int) fpnum
.dbl
.ieee
.mantissa0
) << 32
250 | fpnum
.dbl
.ieee
.mantissa1
);
252 zero_mantissa
= num
== 0;
254 if (sizeof (unsigned long int) > 6)
256 wnumstr
= _itowa_word (num
, wnumbuf
+ (sizeof wnumbuf
) / sizeof (wchar_t), 16,
258 numstr
= _itoa_word (num
, numbuf
+ sizeof numbuf
, 16,
263 wnumstr
= _itowa (num
, wnumbuf
+ sizeof wnumbuf
/ sizeof (wchar_t), 16,
265 numstr
= _itoa (num
, numbuf
+ sizeof numbuf
, 16,
269 /* Fill with zeroes. */
270 while (wnumstr
> wnumbuf
+ (sizeof wnumbuf
- 52) / sizeof (wchar_t))
276 leading
= fpnum
.dbl
.ieee
.exponent
== 0 ? '0' : '1';
278 exponent
= fpnum
.dbl
.ieee
.exponent
;
286 /* This is a denormalized number. */
288 exponent
= IEEE754_DOUBLE_BIAS
- 1;
291 else if (exponent
>= IEEE754_DOUBLE_BIAS
)
294 exponent
-= IEEE754_DOUBLE_BIAS
;
299 exponent
= -(exponent
- IEEE754_DOUBLE_BIAS
);
302 #ifdef PRINT_FPHEX_LONG_DOUBLE
304 PRINT_FPHEX_LONG_DOUBLE
;
307 /* Look for trailing zeroes. */
310 wnumend
= array_end (wnumbuf
);
311 numend
= array_end (numbuf
);
312 while (wnumend
[-1] == L
'0')
318 bool do_round_away
= false;
320 if (precision
!= -1 && precision
< numend
- numstr
)
322 char last_digit
= precision
> 0 ? numstr
[precision
- 1] : leading
;
323 char next_digit
= numstr
[precision
];
324 int last_digit_value
= (last_digit
>= 'A' && last_digit
<= 'F'
325 ? last_digit
- 'A' + 10
326 : (last_digit
>= 'a' && last_digit
<= 'f'
327 ? last_digit
- 'a' + 10
328 : last_digit
- '0'));
329 int next_digit_value
= (next_digit
>= 'A' && next_digit
<= 'F'
330 ? next_digit
- 'A' + 10
331 : (next_digit
>= 'a' && next_digit
<= 'f'
332 ? next_digit
- 'a' + 10
333 : next_digit
- '0'));
334 bool more_bits
= ((next_digit_value
& 7) != 0
335 || precision
+ 1 < numend
- numstr
);
336 int rounding_mode
= get_rounding_mode ();
337 do_round_away
= round_away (negative
, last_digit_value
& 1,
338 next_digit_value
>= 8, more_bits
,
343 precision
= numend
- numstr
;
344 else if (do_round_away
)
350 char ch
= numstr
[cnt
];
351 /* We assume that the digits and the letters are ordered
352 like in ASCII. This is true for the rest of GNU, too. */
355 wnumstr
[cnt
] = (wchar_t) info
->spec
;
356 numstr
[cnt
] = info
->spec
; /* This is tricky,
360 else if (tolower (ch
) < 'f')
374 /* The mantissa so far was fff...f Now increment the
375 leading digit. Here it is again possible that we
378 leading
= info
->spec
;
379 else if (tolower (leading
) < 'f')
389 exponent
= -exponent
;
407 /* Now we can compute the exponent string. */
408 expstr
= _itoa_word (exponent
, expbuf
+ sizeof expbuf
, 10, 0);
409 wexpstr
= _itowa_word (exponent
,
410 wexpbuf
+ sizeof wexpbuf
/ sizeof (wchar_t), 10, 0);
412 /* Now we have all information to compute the size. */
413 width
-= ((negative
|| info
->showsign
|| info
->space
)
415 + 2 + 1 + 0 + precision
+ 1 + 1
416 /* 0x h . hhh P ExpoSign. */
417 + ((expbuf
+ sizeof expbuf
) - expstr
));
420 /* Count the decimal point.
421 A special case when the mantissa or the precision is zero and the `#'
422 is not given. In this case we must not print the decimal point. */
423 if (precision
> 0 || info
->alt
)
424 width
-= wide
? 1 : strlen (decimal
);
426 if (!info
->left
&& info
->pad
!= '0' && width
> 0)
431 else if (info
->showsign
)
433 else if (info
->space
)
437 if ('X' - 'A' == 'x' - 'a')
438 outchar (info
->spec
+ ('x' - 'a'));
440 outchar (info
->spec
== 'A' ? 'X' : 'x');
442 if (!info
->left
&& info
->pad
== '0' && width
> 0)
447 if (precision
> 0 || info
->alt
)
449 const wchar_t *wtmp
= &decimalwc
;
450 PRINT (decimal
, wtmp
, wide
? 1 : strlen (decimal
));
455 ssize_t tofill
= precision
- (numend
- numstr
);
456 PRINT (numstr
, wnumstr
, MIN (numend
- numstr
, precision
));
461 if ('P' - 'A' == 'p' - 'a')
462 outchar (info
->spec
+ ('p' - 'a'));
464 outchar (info
->spec
== 'A' ? 'P' : 'p');
466 outchar (expnegative
? '-' : '+');
468 PRINT (expstr
, wexpstr
, (expbuf
+ sizeof expbuf
) - expstr
);
470 if (info
->left
&& info
->pad
!= '0' && width
> 0)
471 PADN (info
->pad
, width
);