1 /* Print floating point number in hexadecimal notation according to ISO C99.
2 Copyright (C) 1997-2002,2004,2006 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, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
31 #include <locale/localeinfo.h>
33 /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */
36 /* This defines make it possible to use the same code for GNU C library and
37 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) : INTUSE(_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
48 # define FILE _IO_FILE
49 #else /* ! USE_IN_LIBIO */
50 # define PUT(f, s, n) fwrite (s, 1, n, f)
51 # define PAD(f, c, n) __printf_pad (f, c, n)
52 ssize_t
__printf_pad (FILE *, char pad
, int n
) __THROW
; /* In vfprintf.c. */
53 #endif /* USE_IN_LIBIO */
55 /* Macros for doing the actual output. */
60 register const int outc = (ch); \
61 if (putc (outc, fp) == EOF) \
66 #define PRINT(ptr, wptr, len) \
69 register size_t outlen = (len); \
71 while (outlen-- > 0) \
74 while (outlen-- > 0) \
78 #define PADN(ch, len) \
81 if (PAD (fp, ch, len) != len) \
88 # define MIN(a,b) ((a)<(b)?(a):(b))
93 __printf_fphex (FILE *fp
,
94 const struct printf_info
*info
,
95 const void *const *args
)
97 /* The floating-point value to output. */
100 union ieee754_double dbl
;
101 union ieee854_long_double ldbl
;
105 /* Locale-dependent representation of decimal point. */
109 /* "NaN" or "Inf" for the special cases. */
110 const char *special
= NULL
;
111 const wchar_t *wspecial
= NULL
;
113 /* Buffer for the generated number string for the mantissa. The
114 maximal size for the mantissa is 128 bits. */
123 /* The maximal exponent of two in decimal notation has 5 digits. */
131 /* Non-zero is mantissa is zero. */
134 /* The leading digit before the decimal point. */
138 int precision
= info
->prec
;
141 int width
= info
->width
;
143 /* Number of characters written. */
146 /* Nonzero if this is output on a wide character stream. */
147 int wide
= info
->wide
;
150 /* Figure out the decimal point character. */
151 if (info
->extra
== 0)
153 decimal
= _NL_CURRENT (LC_NUMERIC
, DECIMAL_POINT
);
154 decimalwc
= _NL_CURRENT_WORD (LC_NUMERIC
, _NL_NUMERIC_DECIMAL_POINT_WC
);
158 decimal
= _NL_CURRENT (LC_MONETARY
, MON_DECIMAL_POINT
);
159 decimalwc
= _NL_CURRENT_WORD (LC_MONETARY
,
160 _NL_MONETARY_DECIMAL_POINT_WC
);
162 /* The decimal point character must never be zero. */
163 assert (*decimal
!= '\0' && decimalwc
!= L
'\0');
166 /* Fetch the argument value. */
167 #ifndef __NO_LONG_DOUBLE_MATH
168 if (info
->is_long_double
&& sizeof (long double) > sizeof (double))
170 fpnum
.ldbl
.d
= *(const long double *) args
[0];
172 /* Check for special values: not a number or infinity. */
173 if (__isnanl (fpnum
.ldbl
.d
))
175 if (isupper (info
->spec
))
189 if (__isinfl (fpnum
.ldbl
.d
))
191 if (isupper (info
->spec
))
203 negative
= signbit (fpnum
.ldbl
.d
);
207 #endif /* no long double */
209 fpnum
.dbl
.d
= *(const double *) args
[0];
211 /* Check for special values: not a number or infinity. */
212 if (__isnan (fpnum
.dbl
.d
))
214 if (isupper (info
->spec
))
228 if (__isinf (fpnum
.dbl
.d
))
230 if (isupper (info
->spec
))
242 negative
= signbit (fpnum
.dbl
.d
);
248 int width
= info
->width
;
250 if (negative
|| info
->showsign
|| info
->space
)
254 if (!info
->left
&& width
> 0)
259 else if (info
->showsign
)
261 else if (info
->space
)
264 PRINT (special
, wspecial
, 3);
266 if (info
->left
&& width
> 0)
272 if (info
->is_long_double
== 0 || sizeof (double) == sizeof (long double))
274 /* We have 52 bits of mantissa plus one implicit digit. Since
275 52 bits are representable without rest using hexadecimal
276 digits we use only the implicit digits for the number before
277 the decimal point. */
278 unsigned long long int num
;
280 num
= (((unsigned long long int) fpnum
.dbl
.ieee
.mantissa0
) << 32
281 | fpnum
.dbl
.ieee
.mantissa1
);
283 zero_mantissa
= num
== 0;
285 if (sizeof (unsigned long int) > 6)
287 wnumstr
= _itowa_word (num
, wnumbuf
+ (sizeof wnumbuf
) / sizeof (wchar_t), 16,
289 numstr
= _itoa_word (num
, numbuf
+ sizeof numbuf
, 16,
294 wnumstr
= _itowa (num
, wnumbuf
+ sizeof wnumbuf
/ sizeof (wchar_t), 16,
296 numstr
= _itoa (num
, numbuf
+ sizeof numbuf
, 16,
300 /* Fill with zeroes. */
301 while (wnumstr
> wnumbuf
+ (sizeof wnumbuf
- 52) / sizeof (wchar_t))
307 leading
= fpnum
.dbl
.ieee
.exponent
== 0 ? '0' : '1';
309 exponent
= fpnum
.dbl
.ieee
.exponent
;
317 /* This is a denormalized number. */
319 exponent
= IEEE754_DOUBLE_BIAS
- 1;
322 else if (exponent
>= IEEE754_DOUBLE_BIAS
)
325 exponent
-= IEEE754_DOUBLE_BIAS
;
330 exponent
= -(exponent
- IEEE754_DOUBLE_BIAS
);
333 #ifdef PRINT_FPHEX_LONG_DOUBLE
335 PRINT_FPHEX_LONG_DOUBLE
;
338 /* Look for trailing zeroes. */
341 wnumend
= &wnumbuf
[sizeof wnumbuf
/ sizeof wnumbuf
[0]];
342 numend
= &numbuf
[sizeof numbuf
/ sizeof numbuf
[0]];
343 while (wnumend
[-1] == L
'0')
350 precision
= numend
- numstr
;
351 else if (precision
< numend
- numstr
352 && (numstr
[precision
] > '8'
353 || (('A' < '0' || 'a' < '0')
354 && numstr
[precision
] < '0')
355 || (numstr
[precision
] == '8'
356 && (precision
+ 1 < numend
- numstr
359 && ((numstr
[precision
- 1] & 1)
360 ^ (isdigit (numstr
[precision
- 1]) == 0)))
363 ^ (isdigit (leading
) == 0)))))))
369 char ch
= numstr
[cnt
];
370 /* We assume that the digits and the letters are ordered
371 like in ASCII. This is true for the rest of GNU, too. */
374 wnumstr
[cnt
] = (wchar_t) info
->spec
;
375 numstr
[cnt
] = info
->spec
; /* This is tricky,
379 else if (tolower (ch
) < 'f')
393 /* The mantissa so far was fff...f Now increment the
394 leading digit. Here it is again possible that we
397 leading
= info
->spec
;
398 else if (tolower (leading
) < 'f')
408 exponent
= -exponent
;
426 /* Now we can compute the exponent string. */
427 expstr
= _itoa_word (exponent
, expbuf
+ sizeof expbuf
, 10, 0);
428 wexpstr
= _itowa_word (exponent
,
429 wexpbuf
+ sizeof wexpbuf
/ sizeof (wchar_t), 10, 0);
431 /* Now we have all information to compute the size. */
432 width
-= ((negative
|| info
->showsign
|| info
->space
)
434 + 2 + 1 + 0 + precision
+ 1 + 1
435 /* 0x h . hhh P ExpoSign. */
436 + ((expbuf
+ sizeof expbuf
) - expstr
));
439 /* Count the decimal point.
440 A special case when the mantissa or the precision is zero and the `#'
441 is not given. In this case we must not print the decimal point. */
442 if (precision
> 0 || info
->alt
)
443 width
-= wide
? 1 : strlen (decimal
);
445 if (!info
->left
&& info
->pad
!= '0' && width
> 0)
450 else if (info
->showsign
)
452 else if (info
->space
)
456 if ('X' - 'A' == 'x' - 'a')
457 outchar (info
->spec
+ ('x' - 'a'));
459 outchar (info
->spec
== 'A' ? 'X' : 'x');
461 if (!info
->left
&& info
->pad
== '0' && width
> 0)
466 if (precision
> 0 || info
->alt
)
468 const wchar_t *wtmp
= &decimalwc
;
469 PRINT (decimal
, wtmp
, wide
? 1 : strlen (decimal
));
474 ssize_t tofill
= precision
- (numend
- numstr
);
475 PRINT (numstr
, wnumstr
, MIN (numend
- numstr
, precision
));
480 if ('P' - 'A' == 'p' - 'a')
481 outchar (info
->spec
+ ('p' - 'a'));
483 outchar (info
->spec
== 'A' ? 'P' : 'p');
485 outchar (expnegative
? '-' : '+');
487 PRINT (expstr
, wexpstr
, (expbuf
+ sizeof expbuf
) - expstr
);
489 if (info
->left
&& info
->pad
!= '0' && width
> 0)
490 PADN (info
->pad
, width
);