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