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