Home | History | Annotate | Line # | Download | only in printf
printf_fphex.c revision 1.1.1.1
      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       fpnum.value = **(const __float128 **) args[0];
    169 
    170       /* Check for special values: not a number or infinity.  */
    171       if (isnanq (fpnum.value))
    172 	{
    173 	  negative = fpnum.ieee.negative != 0;
    174 	  if (isupper (info->spec))
    175 	    {
    176 	      special = "NAN";
    177 	      wspecial = L_("NAN");
    178 	    }
    179 	  else
    180 	    {
    181 	      special = "nan";
    182 	      wspecial = L_("nan");
    183 	    }
    184 	}
    185       else
    186 	{
    187 	  if (isinfq (fpnum.value))
    188 	    {
    189 	      if (isupper (info->spec))
    190 		{
    191 		  special = "INF";
    192 		  wspecial = L_("INF");
    193 		}
    194 	      else
    195 		{
    196 		  special = "inf";
    197 		  wspecial = L_("inf");
    198 		}
    199 	    }
    200 
    201 	  negative = signbitq (fpnum.value);
    202 	}
    203     }
    204 
    205   if (special)
    206     {
    207       int width = info->width;
    208 
    209       if (negative || info->showsign || info->space)
    210 	--width;
    211       width -= 3;
    212 
    213       if (!info->left && width > 0)
    214 	PADN (' ', width);
    215 
    216       if (negative)
    217 	outchar ('-');
    218       else if (info->showsign)
    219 	outchar ('+');
    220       else if (info->space)
    221 	outchar (' ');
    222 
    223       PRINT (special, wspecial, 3);
    224 
    225       if (info->left && width > 0)
    226 	PADN (' ', width);
    227 
    228       return done;
    229     }
    230 
    231     {
    232       /* We have 112 bits of mantissa plus one implicit digit.  Since
    233 	 112 bits are representable without rest using hexadecimal
    234 	 digits we use only the implicit digits for the number before
    235 	 the decimal point.  */
    236       uint64_t num0, num1;
    237 
    238       assert (sizeof (long double) == 16);
    239 
    240       num0 = (((unsigned long long int) fpnum.ieee.mantissa0) << 32
    241 	      | fpnum.ieee.mantissa1);
    242       num1 = (((unsigned long long int) fpnum.ieee.mantissa2) << 32
    243 	      | fpnum.ieee.mantissa3);
    244 
    245       zero_mantissa = (num0|num1) == 0;
    246 
    247       if (sizeof (unsigned long int) > 6)
    248 	{
    249 	  numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16,
    250 			       info->spec == 'A');
    251 	  wnumstr = _itowa_word (num1,
    252 				 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
    253 				 16, info->spec == 'A');
    254 	}
    255       else
    256 	{
    257 	  numstr = _itoa (num1, numbuf + sizeof numbuf, 16,
    258 			  info->spec == 'A');
    259 	  wnumstr = _itowa (num1,
    260 			    wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
    261 			    16, info->spec == 'A');
    262 	}
    263 
    264       while (numstr > numbuf + (sizeof numbuf - 64 / 4))
    265 	{
    266 	  *--numstr = '0';
    267 	  *--wnumstr = L_('0');
    268 	}
    269 
    270       if (sizeof (unsigned long int) > 6)
    271 	{
    272 	  numstr = _itoa_word (num0, numstr, 16, info->spec == 'A');
    273 	  wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A');
    274 	}
    275       else
    276 	{
    277 	  numstr = _itoa (num0, numstr, 16, info->spec == 'A');
    278 	  wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A');
    279 	}
    280 
    281       /* Fill with zeroes.  */
    282       while (numstr > numbuf + (sizeof numbuf - 112 / 4))
    283 	{
    284 	  *--wnumstr = L_('0');
    285 	  *--numstr = '0';
    286 	}
    287 
    288       leading = fpnum.ieee.exponent == 0 ? '0' : '1';
    289 
    290       exponent = fpnum.ieee.exponent;
    291 
    292       if (exponent == 0)
    293 	{
    294 	  if (zero_mantissa)
    295 	    expnegative = 0;
    296 	  else
    297 	    {
    298 	      /* This is a denormalized number.  */
    299 	      expnegative = 1;
    300 	      exponent = IEEE854_FLOAT128_BIAS - 1;
    301 	    }
    302 	}
    303       else if (exponent >= IEEE854_FLOAT128_BIAS)
    304 	{
    305 	  expnegative = 0;
    306 	  exponent -= IEEE854_FLOAT128_BIAS;
    307 	}
    308       else
    309 	{
    310 	  expnegative = 1;
    311 	  exponent = -(exponent - IEEE854_FLOAT128_BIAS);
    312 	}
    313     }
    314 
    315   /* Look for trailing zeroes.  */
    316   if (! zero_mantissa)
    317     {
    318       wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
    319       numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
    320       while (wnumend[-1] == L_('0'))
    321 	{
    322 	  --wnumend;
    323 	  --numend;
    324 	}
    325 
    326       do_round_away = false;
    327 
    328       if (precision != -1 && precision < numend - numstr)
    329 	{
    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 #ifdef HAVE_FENV_H
    345 	  int rounding_mode = get_rounding_mode ();
    346 	  do_round_away = round_away (negative, last_digit_value & 1,
    347 				      next_digit_value >= 8, more_bits,
    348 				      rounding_mode);
    349 #endif
    350 	}
    351 
    352       if (precision == -1)
    353 	precision = numend - numstr;
    354       else if (do_round_away)
    355 	{
    356 	  /* Round up.  */
    357 	  int cnt = precision;
    358 	  while (--cnt >= 0)
    359 	    {
    360 	      char ch = numstr[cnt];
    361 	      /* We assume that the digits and the letters are ordered
    362 		 like in ASCII.  This is true for the rest of GNU, too.  */
    363 	      if (ch == '9')
    364 		{
    365 		  wnumstr[cnt] = (wchar_t) info->spec;
    366 		  numstr[cnt] = info->spec;	/* This is tricky,
    367 		  				   think about it!  */
    368 		  break;
    369 		}
    370 	      else if (tolower (ch) < 'f')
    371 		{
    372 		  ++numstr[cnt];
    373 		  ++wnumstr[cnt];
    374 		  break;
    375 		}
    376 	      else
    377 		{
    378 		  numstr[cnt] = '0';
    379 		  wnumstr[cnt] = L_('0');
    380 		}
    381 	    }
    382 	  if (cnt < 0)
    383 	    {
    384 	      /* The mantissa so far was fff...f  Now increment the
    385 		 leading digit.  Here it is again possible that we
    386 		 get an overflow.  */
    387 	      if (leading == '9')
    388 		leading = info->spec;
    389 	      else if (tolower (leading) < 'f')
    390 		++leading;
    391 	      else
    392 		{
    393 		  leading = '1';
    394 		  if (expnegative)
    395 		    {
    396 		      exponent -= 4;
    397 		      if (exponent <= 0)
    398 			{
    399 			  exponent = -exponent;
    400 			  expnegative = 0;
    401 			}
    402 		    }
    403 		  else
    404 		    exponent += 4;
    405 		}
    406 	    }
    407 	}
    408     }
    409   else
    410     {
    411       if (precision == -1)
    412 	precision = 0;
    413       numend = numstr;
    414       wnumend = wnumstr;
    415     }
    416 
    417   /* Now we can compute the exponent string.  */
    418   expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
    419   wexpstr = _itowa_word (exponent,
    420 			 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
    421 
    422   /* Now we have all information to compute the size.  */
    423   width -= ((negative || info->showsign || info->space)
    424 	    /* Sign.  */
    425 	    + 2    + 1 + 0 + precision + 1 + 1
    426 	    /* 0x    h   .   hhh         P   ExpoSign.  */
    427 	    + ((expbuf + sizeof expbuf) - expstr));
    428 	    /* Exponent.  */
    429 
    430   /* Count the decimal point.
    431      A special case when the mantissa or the precision is zero and the `#'
    432      is not given.  In this case we must not print the decimal point.  */
    433   if (precision > 0 || info->alt)
    434     width -= wide ? 1 : strlen (decimal);
    435 
    436   if (!info->left && info->pad != '0' && width > 0)
    437     PADN (' ', width);
    438 
    439   if (negative)
    440     outchar ('-');
    441   else if (info->showsign)
    442     outchar ('+');
    443   else if (info->space)
    444     outchar (' ');
    445 
    446   outchar ('0');
    447   if ('X' - 'A' == 'x' - 'a')
    448     outchar (info->spec + ('x' - 'a'));
    449   else
    450     outchar (info->spec == 'A' ? 'X' : 'x');
    451 
    452   if (!info->left && info->pad == '0' && width > 0)
    453     PADN ('0', width);
    454 
    455   outchar (leading);
    456 
    457   if (precision > 0 || info->alt)
    458     {
    459       const wchar_t *wtmp = &decimalwc;
    460       PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
    461     }
    462 
    463   if (precision > 0)
    464     {
    465       ssize_t tofill = precision - (numend - numstr);
    466       PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
    467       if (tofill > 0)
    468 	PADN ('0', tofill);
    469     }
    470 
    471   if ('P' - 'A' == 'p' - 'a')
    472     outchar (info->spec + ('p' - 'a'));
    473   else
    474     outchar (info->spec == 'A' ? 'P' : 'p');
    475 
    476   outchar (expnegative ? '-' : '+');
    477 
    478   PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
    479 
    480   if (info->left && info->pad != '0' && width > 0)
    481     PADN (info->pad, width);
    482 
    483   return done;
    484 }
    485