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 /* Locale-dependent representation of decimal point. */
110 /* "NaN" or "Inf" for the special cases. */
111 const char *special
= NULL
;
112 const wchar_t *wspecial
= NULL
;
114 /* Buffer for the generated number string for the mantissa. The
115 maximal size for the mantissa is 128 bits. */
124 /* The maximal exponent of two in decimal notation has 5 digits. */
132 /* Non-zero is mantissa is zero. */
135 /* The leading digit before the decimal point. */
139 int precision
= info
->prec
;
142 int width
= info
->width
;
144 /* Number of characters written. */
147 /* Nonzero if this is output on a wide character stream. */
148 int wide
= info
->wide
;
151 /* Figure out the decimal point character. */
152 if (info
->extra
== 0)
154 decimal
= _NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
);
155 decimalwc
= _NL_CURRENT_WORD (LC_NUMERIC
, _NL_NUMERIC_DECIMAL_POINT_WC
);
159 decimal
= _NL_CURRENT (LC_MONETARY
, MON_DECIMAL_POINT
);
160 decimalwc
= _NL_CURRENT_WORD (LC_MONETARY
,
161 _NL_MONETARY_DECIMAL_POINT_WC
);
163 /* The decimal point character must never be zero. */
164 assert (*decimal
!= '\0' && decimalwc
!= L
'\0');
166 #define PRINTF_FPHEX_FETCH(FLOAT, VAR) \
168 (VAR) = *(const FLOAT *) args[0]; \
170 /* Check for special values: not a number or infinity. */ \
173 if (isupper (info->spec)) \
188 if (isupper (info->spec)) \
200 negative = signbit (VAR); \
203 /* Fetch the argument value. */
204 #if __HAVE_DISTINCT_FLOAT128
205 if (info
->is_binary128
)
206 PRINTF_FPHEX_FETCH (_Float128
, fpnum
.flt128
)
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
)
214 PRINTF_FPHEX_FETCH (double, fpnum
.dbl
.d
)
216 #undef PRINTF_FPHEX_FETCH
220 int width
= info
->width
;
222 if (negative
|| info
->showsign
|| info
->space
)
226 if (!info
->left
&& width
> 0)
231 else if (info
->showsign
)
233 else if (info
->space
)
236 PRINT (special
, wspecial
, 3);
238 if (info
->left
&& width
> 0)
244 #if __HAVE_DISTINCT_FLOAT128
245 if (info
->is_binary128
)
246 PRINT_FPHEX_FLOAT128
;
249 if (info
->is_long_double
== 0 || sizeof (double) == sizeof (long double))
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
;
257 num
= (((unsigned long long int) fpnum
.dbl
.ieee
.mantissa0
) << 32
258 | fpnum
.dbl
.ieee
.mantissa1
);
260 zero_mantissa
= num
== 0;
262 if (sizeof (unsigned long int) > 6)
264 wnumstr
= _itowa_word (num
, wnumbuf
+ (sizeof wnumbuf
) / sizeof (wchar_t), 16,
266 numstr
= _itoa_word (num
, numbuf
+ sizeof numbuf
, 16,
271 wnumstr
= _itowa (num
, wnumbuf
+ sizeof wnumbuf
/ sizeof (wchar_t), 16,
273 numstr
= _itoa (num
, numbuf
+ sizeof numbuf
, 16,
277 /* Fill with zeroes. */
278 while (wnumstr
> wnumbuf
+ (sizeof wnumbuf
- 52) / sizeof (wchar_t))
284 leading
= fpnum
.dbl
.ieee
.exponent
== 0 ? '0' : '1';
286 exponent
= fpnum
.dbl
.ieee
.exponent
;
294 /* This is a denormalized number. */
296 exponent
= IEEE754_DOUBLE_BIAS
- 1;
299 else if (exponent
>= IEEE754_DOUBLE_BIAS
)
302 exponent
-= IEEE754_DOUBLE_BIAS
;
307 exponent
= -(exponent
- IEEE754_DOUBLE_BIAS
);
310 #ifdef PRINT_FPHEX_LONG_DOUBLE
312 PRINT_FPHEX_LONG_DOUBLE
;
315 /* Look for trailing zeroes. */
318 wnumend
= array_end (wnumbuf
);
319 numend
= array_end (numbuf
);
320 while (wnumend
[-1] == L
'0')
326 bool do_round_away
= false;
328 if (precision
!= -1 && precision
< numend
- numstr
)
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_value
& 1,
346 next_digit_value
>= 8, more_bits
,
351 precision
= numend
- numstr
;
352 else if (do_round_away
)
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. */
363 wnumstr
[cnt
] = (wchar_t) info
->spec
;
364 numstr
[cnt
] = info
->spec
; /* This is tricky,
368 else if (tolower (ch
) < 'f')
382 /* The mantissa so far was fff...f Now increment the
383 leading digit. Here it is again possible that we
386 leading
= info
->spec
;
387 else if (tolower (leading
) < 'f')
397 exponent
= -exponent
;
415 /* Now we can compute the exponent string. */
416 expstr
= _itoa_word (exponent
, expbuf
+ sizeof expbuf
, 10, 0);
417 wexpstr
= _itowa_word (exponent
,
418 wexpbuf
+ sizeof wexpbuf
/ sizeof (wchar_t), 10, 0);
420 /* Now we have all information to compute the size. */
421 width
-= ((negative
|| info
->showsign
|| info
->space
)
423 + 2 + 1 + 0 + precision
+ 1 + 1
424 /* 0x h . hhh P ExpoSign. */
425 + ((expbuf
+ sizeof expbuf
) - expstr
));
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
);
434 if (!info
->left
&& info
->pad
!= '0' && width
> 0)
439 else if (info
->showsign
)
441 else if (info
->space
)
445 if ('X' - 'A' == 'x' - 'a')
446 outchar (info
->spec
+ ('x' - 'a'));
448 outchar (info
->spec
== 'A' ? 'X' : 'x');
450 if (!info
->left
&& info
->pad
== '0' && width
> 0)
455 if (precision
> 0 || info
->alt
)
457 const wchar_t *wtmp
= &decimalwc
;
458 PRINT (decimal
, wtmp
, wide
? 1 : strlen (decimal
));
463 ssize_t tofill
= precision
- (numend
- numstr
);
464 PRINT (numstr
, wnumstr
, MIN (numend
- numstr
, precision
));
469 if ('P' - 'A' == 'p' - 'a')
470 outchar (info
->spec
+ ('p' - 'a'));
472 outchar (info
->spec
== 'A' ? 'P' : 'p');
474 outchar (expnegative
? '-' : '+');
476 PRINT (expstr
, wexpstr
, (expbuf
+ sizeof expbuf
) - expstr
);
478 if (info
->left
&& info
->pad
!= '0' && width
> 0)
479 PADN (info
->pad
, width
);