The Go Programming Language

Text file src/lib9/fmt/fltfmt.c

     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 = 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 = 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	}
   158	
   159	/*
   160	 * format exponent like sprintf(p, "e%+02d", e)
   161	 */
   162	static void
   163	xfmtexp(char *p, int e, int ucase)
   164	{
   165		char se[9];
   166		int i;
   167	
   168		*p++ = ucase ? 'E' : 'e';
   169		if(e < 0) {
   170			*p++ = '-';
   171			e = -e;
   172		} else
   173			*p++ = '+';
   174		i = 0;
   175		while(e) {
   176			se[i++] = e % 10 + '0';
   177			e /= 10;
   178		}
   179		while(i < 2)
   180			se[i++] = '0';
   181		while(i > 0)
   182			*p++ = se[--i];
   183		*p++ = '\0';
   184	}
   185	
   186	/*
   187	 * compute decimal integer m, exp such that:
   188	 *	f = m*10^exp
   189	 *	m is as short as possible with losing exactness
   190	 * assumes special cases (NaN, +Inf, -Inf) have been handled.
   191	 */
   192	static void
   193	xdtoa(double f, char *s, int *exp, int *neg, int *ns)
   194	{
   195		int c, d, e2, e, ee, i, ndigit, oerrno;
   196		char tmp[NSIGNIF+10];
   197		double g;
   198	
   199		oerrno = errno; /* in case strtod smashes errno */
   200	
   201		/*
   202		 * make f non-negative.
   203		 */
   204		*neg = 0;
   205		if(f < 0) {
   206			f = -f;
   207			*neg = 1;
   208		}
   209	
   210		/*
   211		 * must handle zero specially.
   212		 */
   213		if(f == 0){
   214			*exp = 0;
   215			s[0] = '0';
   216			s[1] = '\0';
   217			*ns = 1;
   218			return;
   219		}
   220	
   221		/*
   222		 * find g,e such that f = g*10^e.
   223		 * guess 10-exponent using 2-exponent, then fine tune.
   224		 */
   225		frexp(f, &e2);
   226		e = (int)(e2 * .301029995664);
   227		g = f * pow10(-e);
   228		while(g < 1) {
   229			e--;
   230			g = f * pow10(-e);
   231		}
   232		while(g >= 10) {
   233			e++;
   234			g = f * pow10(-e);
   235		}
   236	
   237		/*
   238		 * convert NSIGNIF digits as a first approximation.
   239		 */
   240		for(i=0; i<NSIGNIF; i++) {
   241			d = (int)g;
   242			s[i] = d+'0';
   243			g = (g-d) * 10;
   244		}
   245		s[i] = 0;
   246	
   247		/*
   248		 * adjust e because s is 314159... not 3.14159...
   249		 */
   250		e -= NSIGNIF-1;
   251		xfmtexp(s+NSIGNIF, e, 0);
   252	
   253		/*
   254		 * adjust conversion until strtod(s) == f exactly.
   255		 */
   256		for(i=0; i<10; i++) {
   257			g = strtod(s, nil);
   258			if(f > g) {
   259				if(xadd1(s, NSIGNIF)) {
   260					/* gained a digit */
   261					e--;
   262					xfmtexp(s+NSIGNIF, e, 0);
   263				}
   264				continue;
   265			}
   266			if(f < g) {
   267				if(xsub1(s, NSIGNIF)) {
   268					/* lost a digit */
   269					e++;
   270					xfmtexp(s+NSIGNIF, e, 0);
   271				}
   272				continue;
   273			}
   274			break;
   275		}
   276	
   277		/*
   278		 * play with the decimal to try to simplify.
   279		 */
   280	
   281		/*
   282		 * bump last few digits up to 9 if we can
   283		 */
   284		for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
   285			c = s[i];
   286			if(c != '9') {
   287				s[i] = '9';
   288				g = strtod(s, nil);
   289				if(g != f) {
   290					s[i] = c;
   291					break;
   292				}
   293			}
   294		}
   295	
   296		/*
   297		 * add 1 in hopes of turning 9s to 0s
   298		 */
   299		if(s[NSIGNIF-1] == '9') {
   300			strcpy(tmp, s);
   301			ee = e;
   302			if(xadd1(tmp, NSIGNIF)) {
   303				ee--;
   304				xfmtexp(tmp+NSIGNIF, ee, 0);
   305			}
   306			g = strtod(tmp, nil);
   307			if(g == f) {
   308				strcpy(s, tmp);
   309				e = ee;
   310			}
   311		}
   312	
   313		/*
   314		 * bump last few digits down to 0 as we can.
   315		 */
   316		for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
   317			c = s[i];
   318			if(c != '0') {
   319				s[i] = '0';
   320				g = strtod(s, nil);
   321				if(g != f) {
   322					s[i] = c;
   323					break;
   324				}
   325			}
   326		}
   327	
   328		/*
   329		 * remove trailing zeros.
   330		 */
   331		ndigit = NSIGNIF;
   332		while(ndigit > 1 && s[ndigit-1] == '0'){
   333			e++;
   334			--ndigit;
   335		}
   336		s[ndigit] = 0;
   337		*exp = e;
   338		*ns = ndigit;
   339		errno = oerrno;
   340	}
   341	
   342	#ifdef PLAN9PORT
   343	static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
   344	#else
   345	static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
   346	#endif
   347	
   348	int
   349	__efgfmt(Fmt *fmt)
   350	{
   351		char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
   352		double f;
   353		int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
   354		int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
   355		Rune r, *rs, *rt;
   356	
   357		if(fmt->flags&FmtLong)
   358			f = va_arg(fmt->args, long double);
   359		else
   360			f = va_arg(fmt->args, double);
   361	
   362		/*
   363		 * extract formatting flags
   364		 */
   365		fl = fmt->flags;
   366		fmt->flags = 0;
   367		prec = FDEFLT;
   368		if(fl & FmtPrec)
   369			prec = fmt->prec;
   370		chr = fmt->r;
   371		ucase = 0;
   372		switch(chr) {
   373		case 'A':
   374		case 'E':
   375		case 'F':
   376		case 'G':
   377			chr += 'a'-'A';
   378			ucase = 1;
   379			break;
   380		}
   381	
   382		/*
   383		 * pick off special numbers.
   384		 */
   385		if(__isNaN(f)) {
   386			s = special[0+ucase];
   387		special:
   388			fmt->flags = fl & (FmtWidth|FmtLeft);
   389			return __fmtcpy(fmt, s, strlen(s), strlen(s));
   390		}
   391		if(__isInf(f, 1)) {
   392			s = special[2+ucase];
   393			goto special;
   394		}
   395		if(__isInf(f, -1)) {
   396			s = special[4+ucase];
   397			goto special;
   398		}
   399	
   400		/*
   401		 * get exact representation.
   402		 */
   403		digits = buf;
   404		xdtoa(f, digits, &exp, &neg, &ndigits);
   405	
   406		/*
   407		 * get locale's decimal point.
   408		 */
   409		dot = fmt->decimal;
   410		if(dot == nil)
   411			dot = ".";
   412		dotwid = utflen(dot);
   413	
   414		/*
   415		 * now the formatting fun begins.
   416		 * compute parameters for actual fmt:
   417		 *
   418		 *	pad: number of spaces to insert before/after field.
   419		 *	z1: number of zeros to insert before digits
   420		 *	z2: number of zeros to insert after digits
   421		 *	point: number of digits to print before decimal point
   422		 *	ndigits: number of digits to use from digits[]
   423		 *	suf: trailing suffix, like "e-5"
   424		 */
   425		realchr = chr;
   426		switch(chr){
   427		case 'g':
   428			/*
   429			 * convert to at most prec significant digits. (prec=0 means 1)
   430			 */
   431			if(prec == 0)
   432				prec = 1;
   433			if(ndigits > prec) {
   434				if(digits[prec] >= '5' && xadd1(digits, prec))
   435					exp++;
   436				exp += ndigits-prec;
   437				ndigits = prec;
   438			}
   439	
   440			/*
   441			 * extra rules for %g (implemented below):
   442			 *	trailing zeros removed after decimal unless FmtSharp.
   443			 *	decimal point only if digit follows.
   444			 */
   445	
   446			/* fall through to %e */
   447		default:
   448		case 'e':
   449			/*
   450			 * one significant digit before decimal, no leading zeros.
   451			 */
   452			point = 1;
   453			z1 = 0;
   454	
   455			/*
   456			 * decimal point is after ndigits digits right now.
   457			 * slide to be after first.
   458			 */
   459			e  = exp + (ndigits-1);
   460	
   461			/*
   462			 * if this is %g, check exponent and convert prec
   463			 */
   464			if(realchr == 'g') {
   465				if(-4 <= e && e < prec)
   466					goto casef;
   467				prec--;	/* one digit before decimal; rest after */
   468			}
   469	
   470			/*
   471			 * compute trailing zero padding or truncate digits.
   472			 */
   473			if(1+prec >= ndigits)
   474				z2 = 1+prec - ndigits;
   475			else {
   476				/*
   477				 * truncate digits
   478				 */
   479				assert(realchr != 'g');
   480				newndigits = 1+prec;
   481				if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
   482					/*
   483					 * had 999e4, now have 100e5
   484					 */
   485					e++;
   486				}
   487				ndigits = newndigits;
   488				z2 = 0;
   489			}
   490			xfmtexp(suf, e, ucase);
   491			sufwid = strlen(suf);
   492			break;
   493	
   494		casef:
   495		case 'f':
   496			/*
   497			 * determine where digits go with respect to decimal point
   498			 */
   499			if(ndigits+exp > 0) {
   500				point = ndigits+exp;
   501				z1 = 0;
   502			} else {
   503				point = 1;
   504				z1 = 1 + -(ndigits+exp);
   505			}
   506	
   507			/*
   508			 * %g specifies prec = number of significant digits
   509			 * convert to number of digits after decimal point
   510			 */
   511			if(realchr == 'g')
   512				prec += z1 - point;
   513	
   514			/*
   515			 * compute trailing zero padding or truncate digits.
   516			 */
   517			if(point+prec >= z1+ndigits)
   518				z2 = point+prec - (z1+ndigits);
   519			else {
   520				/*
   521				 * truncate digits
   522				 */
   523				assert(realchr != 'g');
   524				newndigits = point+prec - z1;
   525				if(newndigits < 0) {
   526					z1 += newndigits;
   527					newndigits = 0;
   528				} else if(newndigits == 0) {
   529					/* perhaps round up */
   530					if(digits[0] >= '5'){
   531						digits[0] = '1';
   532						newndigits = 1;
   533						goto newdigit;
   534					}
   535				} else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
   536					/*
   537					 * digits was 999, is now 100; make it 1000
   538					 */
   539					digits[newndigits++] = '0';
   540				newdigit:
   541					/*
   542					 * account for new digit
   543					 */
   544					if(z1)	/* 0.099 => 0.100 or 0.99 => 1.00*/
   545						z1--;
   546					else	/* 9.99 => 10.00 */
   547						point++;
   548				}
   549				z2 = 0;
   550				ndigits = newndigits;
   551			}
   552			sufwid = 0;
   553			break;
   554		}
   555	
   556		/*
   557		 * if %g is given without FmtSharp, remove trailing zeros.
   558		 * must do after truncation, so that e.g. print %.3g 1.001
   559		 * produces 1, not 1.00.  sorry, but them's the rules.
   560		 */
   561		if(realchr == 'g' && !(fl & FmtSharp)) {
   562			if(z1+ndigits+z2 >= point) {
   563				if(z1+ndigits < point)
   564					z2 = point - (z1+ndigits);
   565				else{
   566					z2 = 0;
   567					while(z1+ndigits > point && digits[ndigits-1] == '0')
   568						ndigits--;
   569				}
   570			}
   571		}
   572	
   573		/*
   574		 * compute width of all digits and decimal point and suffix if any
   575		 */
   576		wid = z1+ndigits+z2;
   577		if(wid > point)
   578			wid += dotwid;
   579		else if(wid == point){
   580			if(fl & FmtSharp)
   581				wid += dotwid;
   582			else
   583				point++;	/* do not print any decimal point */
   584		}
   585		wid += sufwid;
   586	
   587		/*
   588		 * determine sign
   589		 */
   590		sign = 0;
   591		if(neg)
   592			sign = '-';
   593		else if(fl & FmtSign)
   594			sign = '+';
   595		else if(fl & FmtSpace)
   596			sign = ' ';
   597		if(sign)
   598			wid++;
   599	
   600		/*
   601		 * compute padding
   602		 */
   603		pad = 0;
   604		if((fl & FmtWidth) && fmt->width > wid)
   605			pad = fmt->width - wid;
   606		if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
   607			z1 += pad;
   608			point += pad;
   609			pad = 0;
   610		}
   611	
   612		/*
   613		 * format the actual field.  too bad about doing this twice.
   614		 */
   615		if(fmt->runes){
   616			if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
   617				return -1;
   618			rt = (Rune*)fmt->to;
   619			rs = (Rune*)fmt->stop;
   620			if(sign)
   621				FMTRCHAR(fmt, rt, rs, sign);
   622			while(z1>0 || ndigits>0 || z2>0) {
   623				if(z1 > 0){
   624					z1--;
   625					c = '0';
   626				}else if(ndigits > 0){
   627					ndigits--;
   628					c = *digits++;
   629				}else{
   630					z2--;
   631					c = '0';
   632				}
   633				FMTRCHAR(fmt, rt, rs, c);
   634				if(--point == 0) {
   635					for(p = dot; *p; ){
   636						p += chartorune(&r, p);
   637						FMTRCHAR(fmt, rt, rs, r);
   638					}
   639				}
   640			}
   641			fmt->nfmt += rt - (Rune*)fmt->to;
   642			fmt->to = rt;
   643			if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
   644				return -1;
   645			if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
   646				return -1;
   647		}else{
   648			if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
   649				return -1;
   650			t = (char*)fmt->to;
   651			s = (char*)fmt->stop;
   652			if(sign)
   653				FMTCHAR(fmt, t, s, sign);
   654			while(z1>0 || ndigits>0 || z2>0) {
   655				if(z1 > 0){
   656					z1--;
   657					c = '0';
   658				}else if(ndigits > 0){
   659					ndigits--;
   660					c = *digits++;
   661				}else{
   662					z2--;
   663					c = '0';
   664				}
   665				FMTCHAR(fmt, t, s, c);
   666				if(--point == 0)
   667					for(p=dot; *p; p++)
   668						FMTCHAR(fmt, t, s, *p);
   669			}
   670			fmt->nfmt += t - (char*)fmt->to;
   671			fmt->to = t;
   672			if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
   673				return -1;
   674			if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
   675				return -1;
   676		}
   677		return 0;
   678	}
   679	

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.