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