unix/fiss

lib/libfmt/fltfmt.c in master
Repositories | Summary | Log | Files | LICENSE

fltfmt.c (13354B) download


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