1 /*
2 * dolfptoa - do the grunge work of converting an l_fp number to decimal
3 */
4 #include <config.h>
5 #include <stdio.h>
6
7 #include "ntp_fp.h"
8 #include "ntp_stdlib.h"
9
10 char *
dolfptoa(u_int32 fpi,u_int32 fpv,char sign,short ndec,int msec)11 dolfptoa(
12 u_int32 fpi,
13 u_int32 fpv,
14 char sign,
15 short ndec,
16 int msec
17 )
18 {
19 u_char *cp, *cpend, *cpdec;
20 int dec;
21 u_char cbuf[24];
22 char *buf, *bp;
23
24 /*
25 * Get a string buffer before starting
26 */
27 LIB_GETBUF(buf);
28
29 /*
30 * Zero the character buffer
31 */
32 ZERO(cbuf);
33
34 /*
35 * Work on the integral part. This should work reasonable on
36 * all machines with 32 bit arithmetic. Please note that 32 bits
37 * can *always* be represented with at most 10 decimal digits,
38 * including a possible rounding from the fractional part.
39 */
40 cp = cpend = cpdec = &cbuf[10];
41 for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) {
42 /* can add another digit */
43 u_int32 digit;
44
45 digit = fpi;
46 fpi /= 10U;
47 digit -= (fpi << 3) + (fpi << 1); /* i*10 */
48 *--cp = (u_char)digit;
49 }
50
51 /*
52 * Done that, now deal with the problem of the fraction. First
53 * determine the number of decimal places.
54 */
55 dec = ndec;
56 if (dec < 0)
57 dec = 0;
58 if (msec) {
59 dec += 3;
60 cpdec += 3;
61 }
62 if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf))
63 dec = (int)(sizeof(cbuf) - (cpend - cbuf));
64
65 /*
66 * If there's a fraction to deal with, do so.
67 */
68 for (/*NOP*/; dec > 0 && fpv != 0; dec--) {
69 u_int32 digit, tmph, tmpl;
70
71 /*
72 * The scheme here is to multiply the fraction
73 * (0.1234...) by ten. This moves a junk of BCD into
74 * the units part. record that and iterate.
75 * multiply by shift/add in two dwords.
76 */
77 digit = 0;
78 M_LSHIFT(digit, fpv);
79 tmph = digit;
80 tmpl = fpv;
81 M_LSHIFT(digit, fpv);
82 M_LSHIFT(digit, fpv);
83 M_ADD(digit, fpv, tmph, tmpl);
84 *cpend++ = (u_char)digit;
85 }
86
87 /* decide whether to round or simply extend by zeros */
88 if (dec > 0) {
89 /* only '0' digits left -- just reposition end */
90 cpend += dec;
91 } else {
92 /* some bits remain in 'fpv'; do round */
93 u_char *tp = cpend;
94 int carry = ((fpv & 0x80000000) != 0);
95
96 for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) {
97 *--tp += 1;
98 if (*tp == 10)
99 *tp = 0;
100 else
101 carry = FALSE;
102 }
103
104 if (tp < cp) /* rounding from 999 to 1000 or similiar? */
105 cp = tp;
106 }
107
108 /*
109 * We've now got the fraction in cbuf[], with cp pointing at
110 * the first character, cpend pointing past the last, and
111 * cpdec pointing at the first character past the decimal.
112 * Remove leading zeros, then format the number into the
113 * buffer.
114 */
115 while (cp < cpdec && *cp == 0)
116 cp++;
117 if (cp >= cpdec)
118 cp = cpdec - 1;
119
120 bp = buf;
121 if (sign)
122 *bp++ = sign;
123 while (cp < cpend) {
124 if (cp == cpdec)
125 *bp++ = '.';
126 *bp++ = (char)(*cp++) + '0';
127 }
128 *bp = '\0';
129
130 /*
131 * Done!
132 */
133 return buf;
134 }
135
136
137 char *
mfptoa(u_int32 fpi,u_int32 fpf,short ndec)138 mfptoa(
139 u_int32 fpi,
140 u_int32 fpf,
141 short ndec
142 )
143 {
144 int isneg;
145
146 isneg = M_ISNEG(fpi);
147 if (isneg) {
148 M_NEG(fpi, fpf);
149 }
150
151 return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, FALSE);
152 }
153
154
155 char *
mfptoms(u_int32 fpi,u_int32 fpf,short ndec)156 mfptoms(
157 u_int32 fpi,
158 u_int32 fpf,
159 short ndec
160 )
161 {
162 int isneg;
163
164 isneg = M_ISNEG(fpi);
165 if (isneg) {
166 M_NEG(fpi, fpf);
167 }
168
169 return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, TRUE);
170 }
171
172
173