github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/lib9/fmt/fltfmt.c (about)

     1  /*
     2   * The authors of this software are Rob Pike and Ken Thompson,
     3   * with contributions from Mike Burrows and Sean Dorward.
     4   *
     5   *     Copyright (c) 2002-2006 by Lucent Technologies.
     6   *     Portions Copyright (c) 2004 Google Inc.
     7   * 
     8   * Permission to use, copy, modify, and distribute this software for any
     9   * purpose without fee is hereby granted, provided that this entire notice
    10   * is included in all copies of any software which is or includes a copy
    11   * or modification of this software and in all copies of the supporting
    12   * documentation for such software.
    13   * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
    14   * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES 
    15   * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
    16   * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
    17   */
    18  
    19  /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
    20  #include <u.h>
    21  #include <errno.h>
    22  #include <libc.h>
    23  #include "fmtdef.h"
    24  
    25  enum
    26  {
    27  	FDIGIT	= 30,
    28  	FDEFLT	= 6,
    29  	NSIGNIF	= 17
    30  };
    31  
    32  /*
    33   * first few powers of 10, enough for about 1/2 of the
    34   * total space for doubles.
    35   */
    36  static double pows10[] =
    37  {
    38  	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,
    39  	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,
    40  	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,
    41  	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,
    42  	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,
    43  	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,
    44  	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,
    45  	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,
    46  	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,
    47  	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,
    48  	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
    49  	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
    50  	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
    51  	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
    52  	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
    53  	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
    54  };
    55  
    56  #undef	pow10
    57  #define	npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
    58  #define	pow10(x)  fmtpow10(x)
    59  
    60  static double
    61  pow10(int n)
    62  {
    63  	double d;
    64  	int neg;
    65  
    66  	neg = 0;
    67  	if(n < 0){
    68  		neg = 1;
    69  		n = -n;
    70  	}
    71  
    72  	if(n < npows10)
    73  		d = pows10[n];
    74  	else{
    75  		d = pows10[npows10-1];
    76  		for(;;){
    77  			n -= npows10 - 1;
    78  			if(n < npows10){
    79  				d *= pows10[n];
    80  				break;
    81  			}
    82  			d *= pows10[npows10 - 1];
    83  		}
    84  	}
    85  	if(neg)
    86  		return 1./d;
    87  	return d;
    88  }
    89  
    90  /*
    91   * add 1 to the decimal integer string a of length n.
    92   * if 99999 overflows into 10000, return 1 to tell caller
    93   * to move the virtual decimal point.
    94   */
    95  static int
    96  xadd1(char *a, int n)
    97  {
    98  	char *b;
    99  	int c;
   100  
   101  	if(n < 0 || n > NSIGNIF)
   102  		return 0;
   103  	for(b = a+n-1; b >= a; b--) {
   104  		c = *b + 1;
   105  		if(c <= '9') {
   106  			*b = (char)c;
   107  			return 0;
   108  		}
   109  		*b = '0';
   110  	}
   111  	/*
   112  	 * need to overflow adding digit.
   113  	 * shift number down and insert 1 at beginning.
   114  	 * decimal is known to be 0s or we wouldn't
   115  	 * have gotten this far.  (e.g., 99999+1 => 00000)
   116  	 */
   117  	a[0] = '1';
   118  	return 1;
   119  }
   120  
   121  /*
   122   * subtract 1 from the decimal integer string a.
   123   * if 10000 underflows into 09999, make it 99999
   124   * and return 1 to tell caller to move the virtual
   125   * decimal point.  this way, xsub1 is inverse of xadd1.
   126   */
   127  static int
   128  xsub1(char *a, int n)
   129  {
   130  	char *b;
   131  	int c;
   132  
   133  	if(n < 0 || n > NSIGNIF)
   134  		return 0;
   135  	for(b = a+n-1; b >= a; b--) {
   136  		c = *b - 1;
   137  		if(c >= '0') {
   138  			if(c == '0' && b == a) {
   139  				/*
   140  				 * just zeroed the top digit; shift everyone up.
   141  				 * decimal is known to be 9s or we wouldn't
   142  				 * have gotten this far.  (e.g., 10000-1 => 09999)
   143  				 */
   144  				*b = '9';
   145  				return 1;
   146  			}
   147  			*b = (char)c;
   148  			return 0;
   149  		}
   150  		*b = '9';
   151  	}
   152  	/*
   153  	 * can't get here.  the number a is always normalized
   154  	 * so that it has a nonzero first digit.
   155  	 */
   156  	abort();
   157  	return 0;
   158  }
   159  
   160  /*
   161   * format exponent like sprintf(p, "e%+02d", e)
   162   */
   163  static void
   164  xfmtexp(char *p, int e, int ucase)
   165  {
   166  	char se[9];
   167  	int i;
   168  
   169  	*p++ = ucase ? 'E' : 'e';
   170  	if(e < 0) {
   171  		*p++ = '-';
   172  		e = -e;
   173  	} else
   174  		*p++ = '+';
   175  	i = 0;
   176  	while(e) {
   177  		se[i++] = (char)(e % 10 + '0');
   178  		e /= 10;
   179  	}
   180  	while(i < 2)
   181  		se[i++] = '0';
   182  	while(i > 0)
   183  		*p++ = se[--i];
   184  	*p = '\0';
   185  }
   186  
   187  /*
   188   * compute decimal integer m, exp such that:
   189   *	f = m*10^exp
   190   *	m is as short as possible with losing exactness
   191   * assumes special cases (NaN, +Inf, -Inf) have been handled.
   192   */
   193  static void
   194  xdtoa(double f, char *s, int *exp, int *neg, int *ns)
   195  {
   196  	int d, e2, e, ee, i, ndigit;
   197  	int oerrno;
   198  	char c;
   199  	char tmp[NSIGNIF+10];
   200  	double g;
   201  
   202  	oerrno = errno; /* in case strtod smashes errno */
   203  
   204  	/*
   205  	 * make f non-negative.
   206  	 */
   207  	*neg = 0;
   208  	if(f < 0) {
   209  		f = -f;
   210  		*neg = 1;
   211  	}
   212  
   213  	/*
   214  	 * must handle zero specially.
   215  	 */
   216  	if(f == 0){
   217  		*exp = 0;
   218  		s[0] = '0';
   219  		s[1] = '\0';
   220  		*ns = 1;
   221  		return;
   222  	}
   223  
   224  	/*
   225  	 * find g,e such that f = g*10^e.
   226  	 * guess 10-exponent using 2-exponent, then fine tune.
   227  	 */
   228  	frexp(f, &e2);
   229  	e = (int)(e2 * .301029995664);
   230  	g = f * pow10(-e);
   231  	while(g < 1) {
   232  		e--;
   233  		g = f * pow10(-e);
   234  	}
   235  	while(g >= 10) {
   236  		e++;
   237  		g = f * pow10(-e);
   238  	}
   239  
   240  	/*
   241  	 * convert NSIGNIF digits as a first approximation.
   242  	 */
   243  	for(i=0; i<NSIGNIF; i++) {
   244  		d = (int)g;
   245  		s[i] = (char)(d+'0');
   246  		g = (g-d) * 10;
   247  	}
   248  	s[i] = 0;
   249  
   250  	/*
   251  	 * adjust e because s is 314159... not 3.14159...
   252  	 */
   253  	e -= NSIGNIF-1;
   254  	xfmtexp(s+NSIGNIF, e, 0);
   255  
   256  	/*
   257  	 * adjust conversion until strtod(s) == f exactly.
   258  	 */
   259  	for(i=0; i<10; i++) {
   260  		g = strtod(s, nil);
   261  		if(f > g) {
   262  			if(xadd1(s, NSIGNIF)) {
   263  				/* gained a digit */
   264  				e--;
   265  				xfmtexp(s+NSIGNIF, e, 0);
   266  			}
   267  			continue;
   268  		}
   269  		if(f < g) {
   270  			if(xsub1(s, NSIGNIF)) {
   271  				/* lost a digit */
   272  				e++;
   273  				xfmtexp(s+NSIGNIF, e, 0);
   274  			}
   275  			continue;
   276  		}
   277  		break;
   278  	}
   279  
   280  	/*
   281  	 * play with the decimal to try to simplify.
   282  	 */
   283  
   284  	/*
   285  	 * bump last few digits up to 9 if we can
   286  	 */
   287  	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
   288  		c = s[i];
   289  		if(c != '9') {
   290  			s[i] = '9';
   291  			g = strtod(s, nil);
   292  			if(g != f) {
   293  				s[i] = c;
   294  				break;
   295  			}
   296  		}
   297  	}
   298  
   299  	/*
   300  	 * add 1 in hopes of turning 9s to 0s
   301  	 */
   302  	if(s[NSIGNIF-1] == '9') {
   303  		strcpy(tmp, s);
   304  		ee = e;
   305  		if(xadd1(tmp, NSIGNIF)) {
   306  			ee--;
   307  			xfmtexp(tmp+NSIGNIF, ee, 0);
   308  		}
   309  		g = strtod(tmp, nil);
   310  		if(g == f) {
   311  			strcpy(s, tmp);
   312  			e = ee;
   313  		}
   314  	}
   315  
   316  	/*
   317  	 * bump last few digits down to 0 as we can.
   318  	 */
   319  	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
   320  		c = s[i];
   321  		if(c != '0') {
   322  			s[i] = '0';
   323  			g = strtod(s, nil);
   324  			if(g != f) {
   325  				s[i] = c;
   326  				break;
   327  			}
   328  		}
   329  	}
   330  
   331  	/*
   332  	 * remove trailing zeros.
   333  	 */
   334  	ndigit = NSIGNIF;
   335  	while(ndigit > 1 && s[ndigit-1] == '0'){
   336  		e++;
   337  		--ndigit;
   338  	}
   339  	s[ndigit] = 0;
   340  	*exp = e;
   341  	*ns = ndigit;
   342  	errno = oerrno;
   343  }
   344  
   345  #ifdef PLAN9PORT
   346  static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
   347  #else
   348  static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
   349  #endif
   350  
   351  int
   352  __efgfmt(Fmt *fmt)
   353  {
   354  	char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
   355  	double f;
   356  	int c, chr, dotwid, e, exp, ndigits, neg, newndigits;
   357  	int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
   358  	ulong fl;
   359  	Rune r, *rs, *rt;
   360  
   361  	if(fmt->flags&FmtLong)
   362  		f = (double)va_arg(fmt->args, long double);
   363  	else
   364  		f = va_arg(fmt->args, double);
   365  
   366  	/*
   367  	 * extract formatting flags
   368  	 */
   369  	fl = fmt->flags;
   370  	fmt->flags = 0;
   371  	prec = FDEFLT;
   372  	if(fl & FmtPrec)
   373  		prec = fmt->prec;
   374  	chr = (int)fmt->r;
   375  	ucase = 0;
   376  	switch(chr) {
   377  	case 'A':
   378  	case 'E':
   379  	case 'F':
   380  	case 'G':
   381  		chr += 'a'-'A';
   382  		ucase = 1;
   383  		break;
   384  	}
   385  
   386  	/*
   387  	 * pick off special numbers.
   388  	 */
   389  	if(__isNaN(f)) {
   390  		s = special[0+ucase];
   391  	special:
   392  		fmt->flags = fl & (FmtWidth|FmtLeft);
   393  		return __fmtcpy(fmt, s, (int)strlen(s), (int)strlen(s));
   394  	}
   395  	if(__isInf(f, 1)) {
   396  		s = special[2+ucase];
   397  		goto special;
   398  	}
   399  	if(__isInf(f, -1)) {
   400  		s = special[4+ucase];
   401  		goto special;
   402  	}
   403  
   404  	/*
   405  	 * get exact representation.
   406  	 */
   407  	digits = buf;
   408  	xdtoa(f, digits, &exp, &neg, &ndigits);
   409  
   410  	/*
   411  	 * get locale's decimal point.
   412  	 */
   413  	dot = fmt->decimal;
   414  	if(dot == nil)
   415  		dot = ".";
   416  	dotwid = utflen(dot);
   417  
   418  	/*
   419  	 * now the formatting fun begins.
   420  	 * compute parameters for actual fmt:
   421  	 *
   422  	 *	pad: number of spaces to insert before/after field.
   423  	 *	z1: number of zeros to insert before digits
   424  	 *	z2: number of zeros to insert after digits
   425  	 *	point: number of digits to print before decimal point
   426  	 *	ndigits: number of digits to use from digits[]
   427  	 *	suf: trailing suffix, like "e-5"
   428  	 */
   429  	realchr = chr;
   430  	switch(chr){
   431  	case 'g':
   432  		/*
   433  		 * convert to at most prec significant digits. (prec=0 means 1)
   434  		 */
   435  		if(prec == 0)
   436  			prec = 1;
   437  		if(ndigits > prec) {
   438  			if(digits[prec] >= '5' && xadd1(digits, prec))
   439  				exp++;
   440  			exp += ndigits-prec;
   441  			ndigits = prec;
   442  		}
   443  
   444  		/*
   445  		 * extra rules for %g (implemented below):
   446  		 *	trailing zeros removed after decimal unless FmtSharp.
   447  		 *	decimal point only if digit follows.
   448  		 */
   449  
   450  		/* fall through to %e */
   451  	default:
   452  	case 'e':
   453  		/*
   454  		 * one significant digit before decimal, no leading zeros.
   455  		 */
   456  		point = 1;
   457  		z1 = 0;
   458  
   459  		/*
   460  		 * decimal point is after ndigits digits right now.
   461  		 * slide to be after first.
   462  		 */
   463  		e  = exp + (ndigits-1);
   464  
   465  		/*
   466  		 * if this is %g, check exponent and convert prec
   467  		 */
   468  		if(realchr == 'g') {
   469  			if(-4 <= e && e < prec)
   470  				goto casef;
   471  			prec--;	/* one digit before decimal; rest after */
   472  		}
   473  
   474  		/*
   475  		 * compute trailing zero padding or truncate digits.
   476  		 */
   477  		if(1+prec >= ndigits)
   478  			z2 = 1+prec - ndigits;
   479  		else {
   480  			/*
   481  			 * truncate digits
   482  			 */
   483  			assert(realchr != 'g');
   484  			newndigits = 1+prec;
   485  			if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
   486  				/*
   487  				 * had 999e4, now have 100e5
   488  				 */
   489  				e++;
   490  			}
   491  			ndigits = newndigits;
   492  			z2 = 0;
   493  		}
   494  		xfmtexp(suf, e, ucase);
   495  		sufwid = (int)strlen(suf);
   496  		break;
   497  
   498  	casef:
   499  	case 'f':
   500  		/*
   501  		 * determine where digits go with respect to decimal point
   502  		 */
   503  		if(ndigits+exp > 0) {
   504  			point = ndigits+exp;
   505  			z1 = 0;
   506  		} else {
   507  			point = 1;
   508  			z1 = 1 + -(ndigits+exp);
   509  		}
   510  
   511  		/*
   512  		 * %g specifies prec = number of significant digits
   513  		 * convert to number of digits after decimal point
   514  		 */
   515  		if(realchr == 'g')
   516  			prec += z1 - point;
   517  
   518  		/*
   519  		 * compute trailing zero padding or truncate digits.
   520  		 */
   521  		if(point+prec >= z1+ndigits)
   522  			z2 = point+prec - (z1+ndigits);
   523  		else {
   524  			/*
   525  			 * truncate digits
   526  			 */
   527  			assert(realchr != 'g');
   528  			newndigits = point+prec - z1;
   529  			if(newndigits < 0) {
   530  				z1 += newndigits;
   531  				newndigits = 0;
   532  			} else if(newndigits == 0) {
   533  				/* perhaps round up */
   534  				if(digits[0] >= '5'){
   535  					digits[0] = '1';
   536  					newndigits = 1;
   537  					goto newdigit;
   538  				}
   539  			} else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
   540  				/*
   541  				 * digits was 999, is now 100; make it 1000
   542  				 */
   543  				digits[newndigits++] = '0';
   544  			newdigit:
   545  				/*
   546  				 * account for new digit
   547  				 */
   548  				if(z1)	/* 0.099 => 0.100 or 0.99 => 1.00*/
   549  					z1--;
   550  				else	/* 9.99 => 10.00 */
   551  					point++;
   552  			}
   553  			z2 = 0;
   554  			ndigits = newndigits;
   555  		}
   556  		sufwid = 0;
   557  		break;
   558  	}
   559  
   560  	/*
   561  	 * if %g is given without FmtSharp, remove trailing zeros.
   562  	 * must do after truncation, so that e.g. print %.3g 1.001
   563  	 * produces 1, not 1.00.  sorry, but them's the rules.
   564  	 */
   565  	if(realchr == 'g' && !(fl & FmtSharp)) {
   566  		if(z1+ndigits+z2 >= point) {
   567  			if(z1+ndigits < point)
   568  				z2 = point - (z1+ndigits);
   569  			else{
   570  				z2 = 0;
   571  				while(z1+ndigits > point && digits[ndigits-1] == '0')
   572  					ndigits--;
   573  			}
   574  		}
   575  	}
   576  
   577  	/*
   578  	 * compute width of all digits and decimal point and suffix if any
   579  	 */
   580  	wid = z1+ndigits+z2;
   581  	if(wid > point)
   582  		wid += dotwid;
   583  	else if(wid == point){
   584  		if(fl & FmtSharp)
   585  			wid += dotwid;
   586  		else
   587  			point++;	/* do not print any decimal point */
   588  	}
   589  	wid += sufwid;
   590  
   591  	/*
   592  	 * determine sign
   593  	 */
   594  	sign = 0;
   595  	if(neg)
   596  		sign = '-';
   597  	else if(fl & FmtSign)
   598  		sign = '+';
   599  	else if(fl & FmtSpace)
   600  		sign = ' ';
   601  	if(sign)
   602  		wid++;
   603  
   604  	/*
   605  	 * compute padding
   606  	 */
   607  	pad = 0;
   608  	if((fl & FmtWidth) && fmt->width > wid)
   609  		pad = fmt->width - wid;
   610  	if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
   611  		z1 += pad;
   612  		point += pad;
   613  		pad = 0;
   614  	}
   615  
   616  	/*
   617  	 * format the actual field.  too bad about doing this twice.
   618  	 */
   619  	if(fmt->runes){
   620  		if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
   621  			return -1;
   622  		rt = (Rune*)fmt->to;
   623  		rs = (Rune*)fmt->stop;
   624  		if(sign)
   625  			FMTRCHAR(fmt, rt, rs, sign);
   626  		while(z1>0 || ndigits>0 || z2>0) {
   627  			if(z1 > 0){
   628  				z1--;
   629  				c = '0';
   630  			}else if(ndigits > 0){
   631  				ndigits--;
   632  				c = *digits++;
   633  			}else{
   634  				z2--;
   635  				c = '0';
   636  			}
   637  			FMTRCHAR(fmt, rt, rs, c);
   638  			if(--point == 0) {
   639  				for(p = dot; *p; ){
   640  					p += chartorune(&r, p);
   641  					FMTRCHAR(fmt, rt, rs, r);
   642  				}
   643  			}
   644  		}
   645  		fmt->nfmt += (int)(rt - (Rune*)fmt->to);
   646  		fmt->to = rt;
   647  		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
   648  			return -1;
   649  		if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
   650  			return -1;
   651  	}else{
   652  		if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
   653  			return -1;
   654  		t = (char*)fmt->to;
   655  		s = (char*)fmt->stop;
   656  		if(sign)
   657  			FMTCHAR(fmt, t, s, sign);
   658  		while(z1>0 || ndigits>0 || z2>0) {
   659  			if(z1 > 0){
   660  				z1--;
   661  				c = '0';
   662  			}else if(ndigits > 0){
   663  				ndigits--;
   664  				c = *digits++;
   665  			}else{
   666  				z2--;
   667  				c = '0';
   668  			}
   669  			FMTCHAR(fmt, t, s, c);
   670  			if(--point == 0)
   671  				for(p=dot; *p; p++)
   672  					FMTCHAR(fmt, t, s, *p);
   673  		}
   674  		fmt->nfmt += (int)(t - (char*)fmt->to);
   675  		fmt->to = t;
   676  		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
   677  			return -1;
   678  		if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
   679  			return -1;
   680  	}
   681  	return 0;
   682  }
   683