1 /* Print floating point number in hexadecimal notation according to ISO C99.
2 Copyright (C) 1997, 1998, 1999, 2000 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 Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
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) : _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 ? _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
__P ((FILE *, char pad
, int n
)); /* 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
;
342 numend
= numbuf
+ sizeof numbuf
;
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')
423 /* Now we can compute the exponent string. */
424 expstr
= _itoa_word (exponent
, expbuf
+ sizeof expbuf
, 10, 0);
425 wexpstr
= _itowa_word (exponent
, wexpbuf
+ sizeof wexpbuf
, 10, 0);
427 /* Now we have all information to compute the size. */
428 width
-= ((negative
|| info
->showsign
|| info
->space
)
430 + 2 + 1 + 1 + precision
+ 1 + 1
431 /* 0x h . hhh P ExpoSign. */
432 + ((expbuf
+ sizeof expbuf
) - expstr
));
435 /* A special case when the mantissa or the precision is zero and the `#'
436 is not given. In this case we must not print the decimal point. */
437 if (precision
== 0 && !info
->alt
)
438 ++width
; /* This nihilates the +1 for the decimal-point
439 character in the following equation. */
441 if (!info
->left
&& width
> 0)
446 else if (info
->showsign
)
448 else if (info
->space
)
452 if ('X' - 'A' == 'x' - 'a')
453 outchar (info
->spec
+ ('x' - 'a'));
455 outchar (info
->spec
== 'A' ? 'X' : 'x');
458 if (precision
> 0 || info
->alt
)
460 const wchar_t *wtmp
= &decimalwc
;
461 PRINT (decimal
, wtmp
, wide
? 1 : strlen (decimal
));
466 PRINT (numstr
, wnumstr
, MIN (numend
- numstr
, precision
));
467 if (precision
> numend
- numstr
)
468 PADN ('0', precision
- (numend
- numstr
));
471 if (info
->left
&& info
->pad
== '0' && width
> 0)
474 if ('P' - 'A' == 'p' - 'a')
475 outchar (info
->spec
+ ('p' - 'a'));
477 outchar (info
->spec
== 'A' ? 'P' : 'p');
479 outchar (expnegative
? '-' : '+');
481 PRINT (expstr
, wexpstr
, (expbuf
+ sizeof expbuf
) - expstr
);
483 if (info
->left
&& info
->pad
!= '0' && width
> 0)
484 PADN (info
->pad
, width
);