1 /* Print floating point number in hexadecimal notation according to ISO C99.
2 Copyright (C) 1997-2016 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
30 #include <locale/localeinfo.h>
32 #include <rounding-mode.h>
34 /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */
37 /* This defines make it possible to use the same code for GNU C library and
38 the GNU I/O library. */
40 #define PUT(f, s, n) _IO_sputn (f, s, n)
41 #define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : _IO_padn (f, c, n))
42 /* We use this file GNU C library and GNU I/O library. So make
45 #define putc(c, f) (wide \
46 ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
47 #define size_t _IO_size_t
50 /* Macros for doing the actual output. */
55 const int outc = (ch); \
56 if (putc (outc, fp) == EOF) \
61 #define PRINT(ptr, wptr, len) \
64 size_t outlen = (len); \
66 while (outlen-- > 0) \
69 while (outlen-- > 0) \
73 #define PADN(ch, len) \
76 if (PAD (fp, ch, len) != len) \
83 # define MIN(a,b) ((a)<(b)?(a):(b))
88 __printf_fphex (FILE *fp
,
89 const struct printf_info
*info
,
90 const void *const *args
)
92 /* The floating-point value to output. */
95 union ieee754_double dbl
;
100 /* Locale-dependent representation of decimal point. */
104 /* "NaN" or "Inf" for the special cases. */
105 const char *special
= NULL
;
106 const wchar_t *wspecial
= NULL
;
108 /* Buffer for the generated number string for the mantissa. The
109 maximal size for the mantissa is 128 bits. */
118 /* The maximal exponent of two in decimal notation has 5 digits. */
126 /* Non-zero is mantissa is zero. */
129 /* The leading digit before the decimal point. */
133 int precision
= info
->prec
;
136 int width
= info
->width
;
138 /* Number of characters written. */
141 /* Nonzero if this is output on a wide character stream. */
142 int wide
= info
->wide
;
145 /* Figure out the decimal point character. */
146 if (info
->extra
== 0)
148 decimal
= _NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
);
149 decimalwc
= _NL_CURRENT_WORD (LC_NUMERIC
, _NL_NUMERIC_DECIMAL_POINT_WC
);
153 decimal
= _NL_CURRENT (LC_MONETARY
, MON_DECIMAL_POINT
);
154 decimalwc
= _NL_CURRENT_WORD (LC_MONETARY
,
155 _NL_MONETARY_DECIMAL_POINT_WC
);
157 /* The decimal point character must never be zero. */
158 assert (*decimal
!= '\0' && decimalwc
!= L
'\0');
161 /* Fetch the argument value. */
162 #ifndef __NO_LONG_DOUBLE_MATH
163 if (info
->is_long_double
&& sizeof (long double) > sizeof (double))
165 fpnum
.ldbl
= *(const long double *) args
[0];
167 /* Check for special values: not a number or infinity. */
168 if (isnan (fpnum
.ldbl
))
170 if (isupper (info
->spec
))
183 if (isinf (fpnum
.ldbl
))
185 if (isupper (info
->spec
))
197 negative
= signbit (fpnum
.ldbl
);
200 #endif /* no long double */
202 fpnum
.dbl
.d
= *(const double *) args
[0];
204 /* Check for special values: not a number or infinity. */
205 if (isnan (fpnum
.dbl
.d
))
207 if (isupper (info
->spec
))
220 if (isinf (fpnum
.dbl
.d
))
222 if (isupper (info
->spec
))
234 negative
= signbit (fpnum
.dbl
.d
);
239 int width
= info
->width
;
241 if (negative
|| info
->showsign
|| info
->space
)
245 if (!info
->left
&& width
> 0)
250 else if (info
->showsign
)
252 else if (info
->space
)
255 PRINT (special
, wspecial
, 3);
257 if (info
->left
&& width
> 0)
263 if (info
->is_long_double
== 0 || sizeof (double) == sizeof (long double))
265 /* We have 52 bits of mantissa plus one implicit digit. Since
266 52 bits are representable without rest using hexadecimal
267 digits we use only the implicit digits for the number before
268 the decimal point. */
269 unsigned long long int num
;
271 num
= (((unsigned long long int) fpnum
.dbl
.ieee
.mantissa0
) << 32
272 | fpnum
.dbl
.ieee
.mantissa1
);
274 zero_mantissa
= num
== 0;
276 if (sizeof (unsigned long int) > 6)
278 wnumstr
= _itowa_word (num
, wnumbuf
+ (sizeof wnumbuf
) / sizeof (wchar_t), 16,
280 numstr
= _itoa_word (num
, numbuf
+ sizeof numbuf
, 16,
285 wnumstr
= _itowa (num
, wnumbuf
+ sizeof wnumbuf
/ sizeof (wchar_t), 16,
287 numstr
= _itoa (num
, numbuf
+ sizeof numbuf
, 16,
291 /* Fill with zeroes. */
292 while (wnumstr
> wnumbuf
+ (sizeof wnumbuf
- 52) / sizeof (wchar_t))
298 leading
= fpnum
.dbl
.ieee
.exponent
== 0 ? '0' : '1';
300 exponent
= fpnum
.dbl
.ieee
.exponent
;
308 /* This is a denormalized number. */
310 exponent
= IEEE754_DOUBLE_BIAS
- 1;
313 else if (exponent
>= IEEE754_DOUBLE_BIAS
)
316 exponent
-= IEEE754_DOUBLE_BIAS
;
321 exponent
= -(exponent
- IEEE754_DOUBLE_BIAS
);
324 #ifdef PRINT_FPHEX_LONG_DOUBLE
326 PRINT_FPHEX_LONG_DOUBLE
;
329 /* Look for trailing zeroes. */
332 wnumend
= &wnumbuf
[sizeof wnumbuf
/ sizeof wnumbuf
[0]];
333 numend
= &numbuf
[sizeof numbuf
/ sizeof numbuf
[0]];
334 while (wnumend
[-1] == L
'0')
340 bool do_round_away
= false;
342 if (precision
!= -1 && precision
< numend
- numstr
)
344 char last_digit
= precision
> 0 ? numstr
[precision
- 1] : leading
;
345 char next_digit
= numstr
[precision
];
346 int last_digit_value
= (last_digit
>= 'A' && last_digit
<= 'F'
347 ? last_digit
- 'A' + 10
348 : (last_digit
>= 'a' && last_digit
<= 'f'
349 ? last_digit
- 'a' + 10
350 : last_digit
- '0'));
351 int next_digit_value
= (next_digit
>= 'A' && next_digit
<= 'F'
352 ? next_digit
- 'A' + 10
353 : (next_digit
>= 'a' && next_digit
<= 'f'
354 ? next_digit
- 'a' + 10
355 : next_digit
- '0'));
356 bool more_bits
= ((next_digit_value
& 7) != 0
357 || precision
+ 1 < numend
- numstr
);
358 int rounding_mode
= get_rounding_mode ();
359 do_round_away
= round_away (negative
, last_digit_value
& 1,
360 next_digit_value
>= 8, more_bits
,
365 precision
= numend
- numstr
;
366 else if (do_round_away
)
372 char ch
= numstr
[cnt
];
373 /* We assume that the digits and the letters are ordered
374 like in ASCII. This is true for the rest of GNU, too. */
377 wnumstr
[cnt
] = (wchar_t) info
->spec
;
378 numstr
[cnt
] = info
->spec
; /* This is tricky,
382 else if (tolower (ch
) < 'f')
396 /* The mantissa so far was fff...f Now increment the
397 leading digit. Here it is again possible that we
400 leading
= info
->spec
;
401 else if (tolower (leading
) < 'f')
411 exponent
= -exponent
;
429 /* Now we can compute the exponent string. */
430 expstr
= _itoa_word (exponent
, expbuf
+ sizeof expbuf
, 10, 0);
431 wexpstr
= _itowa_word (exponent
,
432 wexpbuf
+ sizeof wexpbuf
/ sizeof (wchar_t), 10, 0);
434 /* Now we have all information to compute the size. */
435 width
-= ((negative
|| info
->showsign
|| info
->space
)
437 + 2 + 1 + 0 + precision
+ 1 + 1
438 /* 0x h . hhh P ExpoSign. */
439 + ((expbuf
+ sizeof expbuf
) - expstr
));
442 /* Count the decimal point.
443 A special case when the mantissa or the precision is zero and the `#'
444 is not given. In this case we must not print the decimal point. */
445 if (precision
> 0 || info
->alt
)
446 width
-= wide
? 1 : strlen (decimal
);
448 if (!info
->left
&& info
->pad
!= '0' && width
> 0)
453 else if (info
->showsign
)
455 else if (info
->space
)
459 if ('X' - 'A' == 'x' - 'a')
460 outchar (info
->spec
+ ('x' - 'a'));
462 outchar (info
->spec
== 'A' ? 'X' : 'x');
464 if (!info
->left
&& info
->pad
== '0' && width
> 0)
469 if (precision
> 0 || info
->alt
)
471 const wchar_t *wtmp
= &decimalwc
;
472 PRINT (decimal
, wtmp
, wide
? 1 : strlen (decimal
));
477 ssize_t tofill
= precision
- (numend
- numstr
);
478 PRINT (numstr
, wnumstr
, MIN (numend
- numstr
, precision
));
483 if ('P' - 'A' == 'p' - 'a')
484 outchar (info
->spec
+ ('p' - 'a'));
486 outchar (info
->spec
== 'A' ? 'P' : 'p');
488 outchar (expnegative
? '-' : '+');
490 PRINT (expstr
, wexpstr
, (expbuf
+ sizeof expbuf
) - expstr
);
492 if (info
->left
&& info
->pad
!= '0' && width
> 0)
493 PADN (info
->pad
, width
);