Home | History | Annotate | Line # | Download | only in printf
printf_fphex.c revision 1.1.1.2
      1 /* Print floating point number in hexadecimal notation according to ISO C99.
      2    Copyright (C) 1997-2012 Free Software Foundation, Inc.
      3    This file is part of the GNU C Library.
      4    Contributed by Ulrich Drepper <drepper (at) cygnus.com>, 1997.
      5 
      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.
     10 
     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.
     15 
     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/>.  */
     19 
     20 #include <config.h>
     21 #include <math.h>
     22 #include <stdlib.h>
     23 #include <stdio.h>
     24 #include <string.h>
     25 #include <stdbool.h>
     26 #define NDEBUG
     27 #include <assert.h>
     28 #include "quadmath-rounding-mode.h"
     29 #include "quadmath-printf.h"
     30 #include "_itoa.h"
     31 #include "_itowa.h"
     32 
     33 
     34 /* Macros for doing the actual output.  */
     36 
     37 #define outchar(ch)							      \
     38   do									      \
     39     {									      \
     40       register const int outc = (ch);					      \
     41       if (PUTC (outc, fp) == EOF)					      \
     42 	return -1;							      \
     43       ++done;								      \
     44     } while (0)
     45 
     46 #define PRINT(ptr, wptr, len)						      \
     47   do									      \
     48     {									      \
     49       register size_t outlen = (len);					      \
     50       if (wide)								      \
     51 	while (outlen-- > 0)						      \
     52 	  outchar (*wptr++);						      \
     53       else								      \
     54 	while (outlen-- > 0)						      \
     55 	  outchar (*ptr++);						      \
     56     } while (0)
     57 
     58 #define PADN(ch, len)							      \
     59   do									      \
     60     {									      \
     61       if (PAD (fp, ch, len) != len)					      \
     62 	return -1;							      \
     63       done += len;							      \
     64     }									      \
     65   while (0)
     66 
     67 
     68 
     70 int
     71 __quadmath_printf_fphex (struct __quadmath_printf_file *fp,
     72 			 const struct printf_info *info,
     73 			 const void *const *args)
     74 {
     75   /* The floating-point value to output.  */
     76   ieee854_float128 fpnum;
     77 
     78   /* Locale-dependent representation of decimal point.	*/
     79   const char *decimal;
     80   wchar_t decimalwc;
     81 
     82   /* "NaN" or "Inf" for the special cases.  */
     83   const char *special = NULL;
     84   const wchar_t *wspecial = NULL;
     85 
     86   /* Buffer for the generated number string for the mantissa.  The
     87      maximal size for the mantissa is 128 bits.  */
     88   char numbuf[32];
     89   char *numstr;
     90   char *numend;
     91   wchar_t wnumbuf[32];
     92   wchar_t *wnumstr;
     93   wchar_t *wnumend;
     94   int negative;
     95 
     96   /* The maximal exponent of two in decimal notation has 5 digits.  */
     97   char expbuf[5];
     98   char *expstr;
     99   wchar_t wexpbuf[5];
    100   wchar_t *wexpstr;
    101   int expnegative;
    102   int exponent;
    103 
    104   /* Non-zero is mantissa is zero.  */
    105   int zero_mantissa;
    106 
    107   /* The leading digit before the decimal point.  */
    108   char leading;
    109 
    110   /* Precision.  */
    111   int precision = info->prec;
    112 
    113   /* Width.  */
    114   int width = info->width;
    115 
    116   /* Number of characters written.  */
    117   int done = 0;
    118 
    119   /* Nonzero if this is output on a wide character stream.  */
    120   int wide = info->wide;
    121 
    122   bool do_round_away;
    123 
    124   /* Figure out the decimal point character.  */
    125 #ifdef USE_NL_LANGINFO
    126   if (info->extra == 0)
    127     decimal = nl_langinfo (DECIMAL_POINT);
    128   else
    129     {
    130       decimal = nl_langinfo (MON_DECIMAL_POINT);
    131       if (*decimal == '\0')
    132 	decimal = nl_langinfo (DECIMAL_POINT);
    133     }
    134   /* The decimal point character must never be zero.  */
    135   assert (*decimal != '\0');
    136 #elif defined USE_LOCALECONV
    137   const struct lconv *lc = localeconv ();
    138   if (info->extra == 0)
    139     decimal = lc->decimal_point;
    140   else
    141     {
    142       decimal = lc->mon_decimal_point;
    143       if (decimal == NULL || *decimal == '\0')
    144 	decimal = lc->decimal_point;
    145     }
    146   if (decimal == NULL || *decimal == '\0')
    147     decimal = ".";
    148 #else
    149   decimal = ".";
    150 #endif
    151 #ifdef USE_NL_LANGINFO_WC
    152   if (info->extra == 0)
    153     decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC);
    154   else
    155     {
    156       decimalwc = nl_langinfo_wc (_NL_MONETARY_DECIMAL_POINT_WC);
    157       if (decimalwc == L_('\0'))
    158 	decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC);
    159     }
    160   /* The decimal point character must never be zero.  */
    161   assert (decimalwc != L_('\0'));
    162 #else
    163   decimalwc = L_('.');
    164 #endif
    165 
    166   /* Fetch the argument value.	*/
    167     {
    168       memcpy (&fpnum.value, *(const void *const *) args[0],
    169 	      sizeof (fpnum.value));
    170 
    171       /* Check for special values: not a number or infinity.  */
    172       if (isnanq (fpnum.value))
    173 	{
    174 	  negative = fpnum.ieee.negative != 0;
    175 	  if (isupper (info->spec))
    176 	    {
    177 	      special = "NAN";
    178 	      wspecial = L_("NAN");
    179 	    }
    180 	  else
    181 	    {
    182 	      special = "nan";
    183 	      wspecial = L_("nan");
    184 	    }
    185 	}
    186       else
    187 	{
    188 	  if (isinfq (fpnum.value))
    189 	    {
    190 	      if (isupper (info->spec))
    191 		{
    192 		  special = "INF";
    193 		  wspecial = L_("INF");
    194 		}
    195 	      else
    196 		{
    197 		  special = "inf";
    198 		  wspecial = L_("inf");
    199 		}
    200 	    }
    201 
    202 	  negative = signbitq (fpnum.value);
    203 	}
    204     }
    205 
    206   if (special)
    207     {
    208       int width = info->width;
    209 
    210       if (negative || info->showsign || info->space)
    211 	--width;
    212       width -= 3;
    213 
    214       if (!info->left && width > 0)
    215 	PADN (' ', width);
    216 
    217       if (negative)
    218 	outchar ('-');
    219       else if (info->showsign)
    220 	outchar ('+');
    221       else if (info->space)
    222 	outchar (' ');
    223 
    224       PRINT (special, wspecial, 3);
    225 
    226       if (info->left && width > 0)
    227 	PADN (' ', width);
    228 
    229       return done;
    230     }
    231 
    232     {
    233       /* We have 112 bits of mantissa plus one implicit digit.  Since
    234 	 112 bits are representable without rest using hexadecimal
    235 	 digits we use only the implicit digits for the number before
    236 	 the decimal point.  */
    237       uint64_t num0, num1;
    238 
    239       assert (sizeof (long double) == 16);
    240 
    241       num0 = (((unsigned long long int) fpnum.ieee.mantissa0) << 32
    242 	      | fpnum.ieee.mantissa1);
    243       num1 = (((unsigned long long int) fpnum.ieee.mantissa2) << 32
    244 	      | fpnum.ieee.mantissa3);
    245 
    246       zero_mantissa = (num0|num1) == 0;
    247 
    248       if (sizeof (unsigned long int) > 6)
    249 	{
    250 	  numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16,
    251 			       info->spec == 'A');
    252 	  wnumstr = _itowa_word (num1,
    253 				 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
    254 				 16, info->spec == 'A');
    255 	}
    256       else
    257 	{
    258 	  numstr = _itoa (num1, numbuf + sizeof numbuf, 16,
    259 			  info->spec == 'A');
    260 	  wnumstr = _itowa (num1,
    261 			    wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
    262 			    16, info->spec == 'A');
    263 	}
    264 
    265       while (numstr > numbuf + (sizeof numbuf - 64 / 4))
    266 	{
    267 	  *--numstr = '0';
    268 	  *--wnumstr = L_('0');
    269 	}
    270 
    271       if (sizeof (unsigned long int) > 6)
    272 	{
    273 	  numstr = _itoa_word (num0, numstr, 16, info->spec == 'A');
    274 	  wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A');
    275 	}
    276       else
    277 	{
    278 	  numstr = _itoa (num0, numstr, 16, info->spec == 'A');
    279 	  wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A');
    280 	}
    281 
    282       /* Fill with zeroes.  */
    283       while (numstr > numbuf + (sizeof numbuf - 112 / 4))
    284 	{
    285 	  *--wnumstr = L_('0');
    286 	  *--numstr = '0';
    287 	}
    288 
    289       leading = fpnum.ieee.exponent == 0 ? '0' : '1';
    290 
    291       exponent = fpnum.ieee.exponent;
    292 
    293       if (exponent == 0)
    294 	{
    295 	  if (zero_mantissa)
    296 	    expnegative = 0;
    297 	  else
    298 	    {
    299 	      /* This is a denormalized number.  */
    300 	      expnegative = 1;
    301 	      exponent = IEEE854_FLOAT128_BIAS - 1;
    302 	    }
    303 	}
    304       else if (exponent >= IEEE854_FLOAT128_BIAS)
    305 	{
    306 	  expnegative = 0;
    307 	  exponent -= IEEE854_FLOAT128_BIAS;
    308 	}
    309       else
    310 	{
    311 	  expnegative = 1;
    312 	  exponent = -(exponent - IEEE854_FLOAT128_BIAS);
    313 	}
    314     }
    315 
    316   /* Look for trailing zeroes.  */
    317   if (! zero_mantissa)
    318     {
    319       wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
    320       numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
    321       while (wnumend[-1] == L_('0'))
    322 	{
    323 	  --wnumend;
    324 	  --numend;
    325 	}
    326 
    327       do_round_away = false;
    328 
    329       if (precision != -1 && precision < numend - numstr)
    330 	{
    331 	  char last_digit = precision > 0 ? numstr[precision - 1] : leading;
    332 	  char next_digit = numstr[precision];
    333 	  int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
    334 				  ? last_digit - 'A' + 10
    335 				  : (last_digit >= 'a' && last_digit <= 'f'
    336 				     ? last_digit - 'a' + 10
    337 				     : last_digit - '0'));
    338 	  int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
    339 				  ? next_digit - 'A' + 10
    340 				  : (next_digit >= 'a' && next_digit <= 'f'
    341 				     ? next_digit - 'a' + 10
    342 				     : next_digit - '0'));
    343 	  bool more_bits = ((next_digit_value & 7) != 0
    344 			    || precision + 1 < numend - numstr);
    345 #ifdef HAVE_FENV_H
    346 	  int rounding_mode = get_rounding_mode ();
    347 	  do_round_away = round_away (negative, last_digit_value & 1,
    348 				      next_digit_value >= 8, more_bits,
    349 				      rounding_mode);
    350 #endif
    351 	}
    352 
    353       if (precision == -1)
    354 	precision = numend - numstr;
    355       else if (do_round_away)
    356 	{
    357 	  /* Round up.  */
    358 	  int cnt = precision;
    359 	  while (--cnt >= 0)
    360 	    {
    361 	      char ch = numstr[cnt];
    362 	      /* We assume that the digits and the letters are ordered
    363 		 like in ASCII.  This is true for the rest of GNU, too.  */
    364 	      if (ch == '9')
    365 		{
    366 		  wnumstr[cnt] = (wchar_t) info->spec;
    367 		  numstr[cnt] = info->spec;	/* This is tricky,
    368 		  				   think about it!  */
    369 		  break;
    370 		}
    371 	      else if (tolower (ch) < 'f')
    372 		{
    373 		  ++numstr[cnt];
    374 		  ++wnumstr[cnt];
    375 		  break;
    376 		}
    377 	      else
    378 		{
    379 		  numstr[cnt] = '0';
    380 		  wnumstr[cnt] = L_('0');
    381 		}
    382 	    }
    383 	  if (cnt < 0)
    384 	    {
    385 	      /* The mantissa so far was fff...f  Now increment the
    386 		 leading digit.  Here it is again possible that we
    387 		 get an overflow.  */
    388 	      if (leading == '9')
    389 		leading = info->spec;
    390 	      else if (tolower (leading) < 'f')
    391 		++leading;
    392 	      else
    393 		{
    394 		  leading = '1';
    395 		  if (expnegative)
    396 		    {
    397 		      exponent -= 4;
    398 		      if (exponent <= 0)
    399 			{
    400 			  exponent = -exponent;
    401 			  expnegative = 0;
    402 			}
    403 		    }
    404 		  else
    405 		    exponent += 4;
    406 		}
    407 	    }
    408 	}
    409     }
    410   else
    411     {
    412       if (precision == -1)
    413 	precision = 0;
    414       numend = numstr;
    415       wnumend = wnumstr;
    416     }
    417 
    418   /* Now we can compute the exponent string.  */
    419   expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
    420   wexpstr = _itowa_word (exponent,
    421 			 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
    422 
    423   /* Now we have all information to compute the size.  */
    424   width -= ((negative || info->showsign || info->space)
    425 	    /* Sign.  */
    426 	    + 2    + 1 + 0 + precision + 1 + 1
    427 	    /* 0x    h   .   hhh         P   ExpoSign.  */
    428 	    + ((expbuf + sizeof expbuf) - expstr));
    429 	    /* Exponent.  */
    430 
    431   /* Count the decimal point.
    432      A special case when the mantissa or the precision is zero and the `#'
    433      is not given.  In this case we must not print the decimal point.  */
    434   if (precision > 0 || info->alt)
    435     width -= wide ? 1 : strlen (decimal);
    436 
    437   if (!info->left && info->pad != '0' && width > 0)
    438     PADN (' ', width);
    439 
    440   if (negative)
    441     outchar ('-');
    442   else if (info->showsign)
    443     outchar ('+');
    444   else if (info->space)
    445     outchar (' ');
    446 
    447   outchar ('0');
    448   if ('X' - 'A' == 'x' - 'a')
    449     outchar (info->spec + ('x' - 'a'));
    450   else
    451     outchar (info->spec == 'A' ? 'X' : 'x');
    452 
    453   if (!info->left && info->pad == '0' && width > 0)
    454     PADN ('0', width);
    455 
    456   outchar (leading);
    457 
    458   if (precision > 0 || info->alt)
    459     {
    460       const wchar_t *wtmp = &decimalwc;
    461       PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
    462     }
    463 
    464   if (precision > 0)
    465     {
    466       ssize_t tofill = precision - (numend - numstr);
    467       PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
    468       if (tofill > 0)
    469 	PADN ('0', tofill);
    470     }
    471 
    472   if ('P' - 'A' == 'p' - 'a')
    473     outchar (info->spec + ('p' - 'a'));
    474   else
    475     outchar (info->spec == 'A' ? 'P' : 'p');
    476 
    477   outchar (expnegative ? '-' : '+');
    478 
    479   PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
    480 
    481   if (info->left && info->pad != '0' && width > 0)
    482     PADN (info->pad, width);
    483 
    484   return done;
    485 }
    486