⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 printf_fp.c

📁 绝对正真的stdio.h的实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Floating point output for `printf'.   Copyright (C) 1995-1999,2000,2001,2002,2003 Free Software Foundation, Inc.   This file is part of the GNU C Library.   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Lesser General Public   License as published by the Free Software Foundation; either   version 2.1 of the License, or (at your option) any later version.   The GNU C Library is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   Lesser General Public License for more details.   You should have received a copy of the GNU Lesser General Public   License along with the GNU C Library; if not, write to the Free   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307 USA.  *//* The gmp headers need some configuration frobs.  */#define HAVE_ALLOCA 1#include <libioP.h>#include <alloca.h>#include <ctype.h>#include <float.h>#include <gmp-mparam.h>#include <gmp.h>#include <stdlib/gmp-impl.h>#include <stdlib/longlong.h>#include <stdlib/fpioconst.h>#include <locale/localeinfo.h>#include <limits.h>#include <math.h>#include <printf.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <wchar.h>#ifdef COMPILE_WPRINTF# define CHAR_T        wchar_t#else# define CHAR_T        char#endif#include "_i18n_number.h"#ifndef NDEBUG# define NDEBUG			/* Undefine this for debugging assertions.  */#endif#include <assert.h>/* This defines make it possible to use the same code for GNU C library and   the GNU I/O library.	 */#define PUT(f, s, n) _IO_sputn (f, s, n)#define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : INTUSE(_IO_padn) (f, c, n))/* We use this file GNU C library and GNU I/O library.	So make   names equal.	 */#undef putc#define putc(c, f) (wide \		    ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))#define size_t     _IO_size_t#define FILE	     _IO_FILE/* Macros for doing the actual output.  */#define outchar(ch)							      \  do									      \    {									      \      register const int outc = (ch);					      \      if (putc (outc, fp) == EOF)					      \	return -1;							      \      ++done;								      \    } while (0)#define PRINT(ptr, wptr, len)						      \  do									      \    {									      \      register size_t outlen = (len);					      \      if (len > 20)							      \	{								      \	  if (PUT (fp, wide ? (const char *) wptr : ptr, outlen) != outlen)   \	    return -1;							      \	  ptr += outlen;						      \	  done += outlen;						      \	}								      \      else								      \	{								      \	  if (wide)							      \	    while (outlen-- > 0)					      \	      outchar (*wptr++);					      \	  else								      \	    while (outlen-- > 0)					      \	      outchar (*ptr++);						      \	}								      \    } while (0)#define PADN(ch, len)							      \  do									      \    {									      \      if (PAD (fp, ch, len) != len)					      \	return -1;							      \      done += len;							      \    }									      \  while (0)/* We use the GNU MP library to handle large numbers.   An MP variable occupies a varying number of entries in its array.  We keep   track of this number for efficiency reasons.  Otherwise we would always   have to process the whole array.  */#define MPN_VAR(name) mp_limb_t *name; mp_size_t name##size#define MPN_ASSIGN(dst,src)						      \  memcpy (dst, src, (dst##size = src##size) * sizeof (mp_limb_t))#define MPN_GE(u,v) \  (u##size > v##size || (u##size == v##size && __mpn_cmp (u, v, u##size) >= 0))extern int __isinfl_internal (long double) attribute_hidden;extern int __isnanl_internal (long double) attribute_hidden;extern mp_size_t __mpn_extract_double (mp_ptr res_ptr, mp_size_t size,				       int *expt, int *is_neg,				       double value);extern mp_size_t __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size,					    int *expt, int *is_neg,					    long double value);extern unsigned int __guess_grouping (unsigned int intdig_max,				      const char *grouping);static wchar_t *group_number (wchar_t *buf, wchar_t *bufend,			      unsigned int intdig_no, const char *grouping,			      wchar_t thousands_sep, int ngroups)     internal_function;int__printf_fp (FILE *fp,	     const struct printf_info *info,	     const void *const *args){  /* The floating-point value to output.  */  union    {      double dbl;      __long_double_t ldbl;    }  fpnum;  /* Locale-dependent representation of decimal point.	*/  const char *decimal;  wchar_t decimalwc;  /* Locale-dependent thousands separator and grouping specification.  */  const char *thousands_sep = NULL;  wchar_t thousands_sepwc = 0;  const char *grouping;  /* "NaN" or "Inf" for the special cases.  */  const char *special = NULL;  const wchar_t *wspecial = NULL;  /* We need just a few limbs for the input before shifting to the right     position.	*/  mp_limb_t fp_input[(LDBL_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB];  /* We need to shift the contents of fp_input by this amount of bits.	*/  int to_shift = 0;  /* The fraction of the floting-point value in question  */  MPN_VAR(frac);  /* and the exponent.	*/  int exponent;  /* Sign of the exponent.  */  int expsign = 0;  /* Sign of float number.  */  int is_neg = 0;  /* Scaling factor.  */  MPN_VAR(scale);  /* Temporary bignum value.  */  MPN_VAR(tmp);  /* Digit which is result of last hack_digit() call.  */  wchar_t digit;  /* The type of output format that will be used: 'e'/'E' or 'f'.  */  int type;  /* Counter for number of written characters.	*/  int done = 0;  /* General helper (carry limb).  */  mp_limb_t cy;  /* Nonzero if this is output on a wide character stream.  */  int wide = info->wide;  auto wchar_t hack_digit (void);  wchar_t hack_digit (void)    {      mp_limb_t hi;      if (expsign != 0 && type == 'f' && exponent-- > 0)	hi = 0;      else if (scalesize == 0)	{	  hi = frac[fracsize - 1];	  frac[fracsize - 1] = __mpn_mul_1 (frac, frac, fracsize - 1, 10);	}      else	{	  if (fracsize < scalesize)	    hi = 0;	  else	    {	      hi = mpn_divmod (tmp, frac, fracsize, scale, scalesize);	      tmp[fracsize - scalesize] = hi;	      hi = tmp[0];	      fracsize = scalesize;	      while (fracsize != 0 && frac[fracsize - 1] == 0)		--fracsize;	      if (fracsize == 0)		{		  /* We're not prepared for an mpn variable with zero		     limbs.  */		  fracsize = 1;		  return L'0' + hi;		}	    }	  mp_limb_t _cy = __mpn_mul_1 (frac, frac, fracsize, 10);	  if (_cy != 0)	    frac[fracsize++] = _cy;	}      return L'0' + hi;    }  /* Figure out the decimal point character.  */  if (info->extra == 0)    {      decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);      decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);    }  else    {      decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT);      if (*decimal == '\0')	decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);      decimalwc = _NL_CURRENT_WORD (LC_MONETARY,				    _NL_MONETARY_DECIMAL_POINT_WC);      if (decimalwc == L'\0')	decimalwc = _NL_CURRENT_WORD (LC_NUMERIC,				      _NL_NUMERIC_DECIMAL_POINT_WC);    }  /* The decimal point character must not be zero.  */  assert (*decimal != '\0');  assert (decimalwc != L'\0');  if (info->group)    {      if (info->extra == 0)	grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);      else	grouping = _NL_CURRENT (LC_MONETARY, MON_GROUPING);      if (*grouping <= 0 || *grouping == CHAR_MAX)	grouping = NULL;      else	{	  /* Figure out the thousands separator character.  */	  if (wide)	    {	      if (info->extra == 0)		thousands_sepwc =		  _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);	      else		thousands_sepwc =		  _NL_CURRENT_WORD (LC_MONETARY,				    _NL_MONETARY_THOUSANDS_SEP_WC);	    }	  else	    {	      if (info->extra == 0)		thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);	      else		thousands_sep = _NL_CURRENT (LC_MONETARY, MON_THOUSANDS_SEP);	    }	  if ((wide && thousands_sepwc == L'\0')	      || (! wide && *thousands_sep == '\0'))	    grouping = NULL;	  else if (thousands_sepwc == L'\0')	    /* If we are printing multibyte characters and there is a	       multibyte representation for the thousands separator,	       we must ensure the wide character thousands separator	       is available, even if it is fake.  */	    thousands_sepwc = 0xfffffffe;	}    }  else    grouping = NULL;  /* Fetch the argument value.	*/#ifndef __NO_LONG_DOUBLE_MATH  if (info->is_long_double && sizeof (long double) > sizeof (double))    {      fpnum.ldbl = *(const long double *) args[0];      /* Check for special values: not a number or infinity.  */      if (__isnanl (fpnum.ldbl))	{	  if (isupper (info->spec))	    {	      special = "NAN";	      wspecial = L"NAN";	    }	    else	      {		special = "nan";		wspecial = L"nan";	      }	  is_neg = 0;	}      else if (__isinfl (fpnum.ldbl))	{	  if (isupper (info->spec))	    {	      special = "INF";	      wspecial = L"INF";	    }	  else	    {	      special = "inf";	      wspecial = L"inf";	    }	  is_neg = fpnum.ldbl < 0;	}      else	{	  fracsize = __mpn_extract_long_double (fp_input,						(sizeof (fp_input) /						 sizeof (fp_input[0])),						&exponent, &is_neg,						fpnum.ldbl);	  to_shift = 1 + fracsize * BITS_PER_MP_LIMB - LDBL_MANT_DIG;	}    }  else#endif	/* no long double */    {      fpnum.dbl = *(const double *) args[0];      /* Check for special values: not a number or infinity.  */      if (__isnan (fpnum.dbl))	{	  is_neg = 0;	  if (isupper (info->spec))	    {	      special = "NAN";	      wspecial = L"NAN";	    }	  else	    {	      special = "nan";	      wspecial = L"nan";	    }	}      else if (__isinf (fpnum.dbl))	{	  is_neg = fpnum.dbl < 0;	  if (isupper (info->spec))	    {	      special = "INF";	      wspecial = L"INF";	    }	  else	    {	      special = "inf";	      wspecial = L"inf";	    }	}      else	{	  fracsize = __mpn_extract_double (fp_input,					   (sizeof (fp_input)					    / sizeof (fp_input[0])),					   &exponent, &is_neg, fpnum.dbl);	  to_shift = 1 + fracsize * BITS_PER_MP_LIMB - DBL_MANT_DIG;	}    }  if (special)    {      int width = info->width;      if (is_neg || info->showsign || info->space)	--width;      width -= 3;      if (!info->left && width > 0)	PADN (' ', width);      if (is_neg)	outchar ('-');      else if (info->showsign)	outchar ('+');

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -