dolfptoa.c revision 293896
1193323Sed/*
2193323Sed * dolfptoa - do the grunge work of converting an l_fp number to decimal
3193323Sed */
4193323Sed#include <config.h>
5193323Sed#include <stdio.h>
6193323Sed
7193323Sed#include "ntp_fp.h"
8193323Sed#include "lib_strbuf.h"
9193323Sed#include "ntp_string.h"
10193323Sed#include "ntp_stdlib.h"
11193323Sed
12193323Sedchar *
13193323Seddolfptoa(
14245431Sdim	u_int32 fpi,
15245431Sdim	u_int32 fpv,
16252723Sdim	int neg,
17252723Sdim	short ndec,
18252723Sdim	int msec
19252723Sdim	)
20252723Sdim{
21252723Sdim	u_char *cp, *cpend, *cpdec;
22210299Sed	int dec;
23198090Srdivacky	u_char cbuf[24];
24198090Srdivacky	char *buf, *bp;
25193323Sed
26193323Sed	/*
27193323Sed	 * Get a string buffer before starting
28193323Sed	 */
29193323Sed	LIB_GETBUF(buf);
30226890Sdim
31193323Sed	/*
32224145Sdim	 * Zero the character buffer
33193323Sed	 */
34193323Sed	ZERO(cbuf);
35193323Sed
36193323Sed	/*
37193323Sed	 * Work on the integral part. This should work reasonable on
38193323Sed	 * all machines with 32 bit arithmetic. Please note that 32 bits
39193323Sed	 * can *always* be represented with at most 10 decimal digits,
40193323Sed	 * including a possible rounding from the fractional part.
41193323Sed	 */
42193323Sed	cp = cpend = cpdec = &cbuf[10];
43193323Sed	for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) {
44193323Sed		/* can add another digit */
45198090Srdivacky		u_int32 digit;
46193323Sed
47193323Sed		digit  = fpi;
48193323Sed		fpi   /= 10U;
49198090Srdivacky		digit -= (fpi << 3) + (fpi << 1); /* i*10 */
50193323Sed		*--cp  = (u_char)digit;
51193323Sed	}
52193323Sed
53193323Sed	/*
54193323Sed	 * Done that, now deal with the problem of the fraction.  First
55193323Sed	 * determine the number of decimal places.
56193323Sed	 */
57193323Sed	dec = ndec;
58193323Sed	if (dec < 0)
59193323Sed		dec = 0;
60193323Sed	if (msec) {
61193323Sed		dec   += 3;
62193323Sed		cpdec += 3;
63193323Sed	}
64193323Sed	if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf))
65193323Sed		dec = (int)(sizeof(cbuf) - (cpend - cbuf));
66193323Sed
67226890Sdim	/*
68195098Sed	 * If there's a fraction to deal with, do so.
69195098Sed	 */
70195098Sed	for (/*NOP*/;  dec > 0 && fpv != 0;  dec--)  {
71195098Sed		u_int32 digit, tmph, tmpl;
72224145Sdim
73195098Sed		/*
74195098Sed		 * The scheme here is to multiply the fraction
75195098Sed		 * (0.1234...) by ten.  This moves a junk of BCD into
76195098Sed		 * the units part.  record that and iterate.
77193323Sed		 * multiply by shift/add in two dwords.
78193323Sed		 */
79193323Sed		digit = 0;
80224145Sdim		M_LSHIFT(digit, fpv);
81193323Sed		tmph = digit;
82193323Sed		tmpl = fpv;
83193323Sed		M_LSHIFT(digit, fpv);
84193323Sed		M_LSHIFT(digit, fpv);
85193323Sed		M_ADD(digit, fpv, tmph, tmpl);
86193323Sed		*cpend++ = (u_char)digit;
87208599Srdivacky	}
88218893Sdim
89218893Sdim	/* decide whether to round or simply extend by zeros */
90218893Sdim	if (dec > 0) {
91218893Sdim		/* only '0' digits left -- just reposition end */
92218893Sdim		cpend += dec;
93208599Srdivacky	} else {
94208599Srdivacky		/* some bits remain in 'fpv'; do round */
95193323Sed		u_char *tp    = cpend;
96198090Srdivacky		int     carry = ((fpv & 0x80000000) != 0);
97193323Sed
98193323Sed		for (dec = (int)(tp - cbuf);  carry && dec > 0;  dec--) {
99193323Sed			*--tp += 1;
100193323Sed			if (*tp == 10)
101193323Sed				*tp = 0;
102193323Sed			else
103198090Srdivacky				carry = FALSE;
104193323Sed		}
105193323Sed
106193323Sed		if (tp < cp) /* rounding from 999 to 1000 or similiar? */
107198090Srdivacky			cp = tp;
108193323Sed	}
109193323Sed
110193323Sed	/*
111198090Srdivacky	 * We've now got the fraction in cbuf[], with cp pointing at
112193323Sed	 * the first character, cpend pointing past the last, and
113193323Sed	 * cpdec pointing at the first character past the decimal.
114198090Srdivacky	 * Remove leading zeros, then format the number into the
115198090Srdivacky	 * buffer.
116198090Srdivacky	 */
117198090Srdivacky	while (cp < cpdec && *cp == 0)
118198090Srdivacky		cp++;
119193323Sed	if (cp >= cpdec)
120193323Sed		cp = cpdec - 1;
121198090Srdivacky
122198090Srdivacky	bp = buf;
123198090Srdivacky	if (neg)
124198090Srdivacky		*bp++ = '-';
125198090Srdivacky	while (cp < cpend) {
126193323Sed		if (cp == cpdec)
127193323Sed			*bp++ = '.';
128198090Srdivacky		*bp++ = (char)(*cp++) + '0';
129198090Srdivacky	}
130198090Srdivacky	*bp = '\0';
131198090Srdivacky
132198090Srdivacky	/*
133193323Sed	 * Done!
134193323Sed	 */
135193323Sed	return buf;
136193323Sed}
137193323Sed
138193323Sed
139193323Sedchar *
140193323Sedmfptoa(
141193323Sed	u_int32	fpi,
142193323Sed	u_int32	fpf,
143193323Sed	short	ndec
144193323Sed	)
145193323Sed{
146193323Sed	int	isneg;
147193323Sed
148193323Sed	isneg = M_ISNEG(fpi);
149193323Sed	if (isneg) {
150193323Sed		M_NEG(fpi, fpf);
151193323Sed	}
152193323Sed
153193323Sed	return dolfptoa(fpi, fpf, isneg, ndec, FALSE);
154193323Sed}
155193323Sed
156193323Sed
157193323Sedchar *
158193323Sedmfptoms(
159193323Sed	u_int32	fpi,
160193323Sed	u_int32	fpf,
161193323Sed	short	ndec
162193323Sed	)
163193323Sed{
164193323Sed	int	isneg;
165193323Sed
166198090Srdivacky	isneg = M_ISNEG(fpi);
167203954Srdivacky	if (isneg) {
168193323Sed		M_NEG(fpi, fpf);
169193323Sed	}
170193323Sed
171193323Sed	return dolfptoa(fpi, fpf, isneg, ndec, TRUE);
172193323Sed}
173193323Sed
174198090Srdivacky
175193323Sed