/src/ntp-dev/libntp/dolfptoa.c
Line | Count | Source |
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 * |
11 | | dolfptoa( |
12 | | u_int32 fpi, |
13 | | u_int32 fpv, |
14 | | char sign, |
15 | | short ndec, |
16 | | int msec |
17 | | ) |
18 | 0 | { |
19 | 0 | u_char *cp, *cpend, *cpdec; |
20 | 0 | int dec; |
21 | 0 | u_char cbuf[24]; |
22 | 0 | char *buf, *bp; |
23 | | |
24 | | /* |
25 | | * Get a string buffer before starting |
26 | | */ |
27 | 0 | LIB_GETBUF(buf); |
28 | | |
29 | | /* |
30 | | * Zero the character buffer |
31 | | */ |
32 | 0 | 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 | 0 | cp = cpend = cpdec = &cbuf[10]; |
41 | 0 | for (dec = (int)(cp - cbuf); dec > 0 && fpi != 0; dec--) { |
42 | | /* can add another digit */ |
43 | 0 | u_int32 digit; |
44 | | |
45 | 0 | digit = fpi; |
46 | 0 | fpi /= 10U; |
47 | 0 | digit -= (fpi << 3) + (fpi << 1); /* i*10 */ |
48 | 0 | *--cp = (u_char)digit; |
49 | 0 | } |
50 | | |
51 | | /* |
52 | | * Done that, now deal with the problem of the fraction. First |
53 | | * determine the number of decimal places. |
54 | | */ |
55 | 0 | dec = ndec; |
56 | 0 | if (dec < 0) |
57 | 0 | dec = 0; |
58 | 0 | if (msec) { |
59 | 0 | dec += 3; |
60 | 0 | cpdec += 3; |
61 | 0 | } |
62 | 0 | if ((size_t)dec > sizeof(cbuf) - (cpend - cbuf)) |
63 | 0 | dec = (int)(sizeof(cbuf) - (cpend - cbuf)); |
64 | | |
65 | | /* |
66 | | * If there's a fraction to deal with, do so. |
67 | | */ |
68 | 0 | for (/*NOP*/; dec > 0 && fpv != 0; dec--) { |
69 | 0 | 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 | 0 | digit = 0; |
78 | 0 | M_LSHIFT(digit, fpv); |
79 | 0 | tmph = digit; |
80 | 0 | tmpl = fpv; |
81 | 0 | M_LSHIFT(digit, fpv); |
82 | 0 | M_LSHIFT(digit, fpv); |
83 | 0 | M_ADD(digit, fpv, tmph, tmpl); |
84 | 0 | *cpend++ = (u_char)digit; |
85 | 0 | } |
86 | | |
87 | | /* decide whether to round or simply extend by zeros */ |
88 | 0 | if (dec > 0) { |
89 | | /* only '0' digits left -- just reposition end */ |
90 | 0 | cpend += dec; |
91 | 0 | } else { |
92 | | /* some bits remain in 'fpv'; do round */ |
93 | 0 | u_char *tp = cpend; |
94 | 0 | int carry = ((fpv & 0x80000000) != 0); |
95 | |
|
96 | 0 | for (dec = (int)(tp - cbuf); carry && dec > 0; dec--) { |
97 | 0 | *--tp += 1; |
98 | 0 | if (*tp == 10) |
99 | 0 | *tp = 0; |
100 | 0 | else |
101 | 0 | carry = FALSE; |
102 | 0 | } |
103 | |
|
104 | 0 | if (tp < cp) /* rounding from 999 to 1000 or similiar? */ |
105 | 0 | cp = tp; |
106 | 0 | } |
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 | 0 | while (cp < cpdec && *cp == 0) |
116 | 0 | cp++; |
117 | 0 | if (cp >= cpdec) |
118 | 0 | cp = cpdec - 1; |
119 | |
|
120 | 0 | bp = buf; |
121 | 0 | if (sign) |
122 | 0 | *bp++ = sign; |
123 | 0 | while (cp < cpend) { |
124 | 0 | if (cp == cpdec) |
125 | 0 | *bp++ = '.'; |
126 | 0 | *bp++ = (char)(*cp++) + '0'; |
127 | 0 | } |
128 | 0 | *bp = '\0'; |
129 | | |
130 | | /* |
131 | | * Done! |
132 | | */ |
133 | 0 | return buf; |
134 | 0 | } |
135 | | |
136 | | |
137 | | char * |
138 | | mfptoa( |
139 | | u_int32 fpi, |
140 | | u_int32 fpf, |
141 | | short ndec |
142 | | ) |
143 | 0 | { |
144 | 0 | int isneg; |
145 | |
|
146 | 0 | isneg = M_ISNEG(fpi); |
147 | 0 | if (isneg) { |
148 | 0 | M_NEG(fpi, fpf); |
149 | 0 | } |
150 | |
|
151 | 0 | return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, FALSE); |
152 | 0 | } |
153 | | |
154 | | |
155 | | char * |
156 | | mfptoms( |
157 | | u_int32 fpi, |
158 | | u_int32 fpf, |
159 | | short ndec |
160 | | ) |
161 | 0 | { |
162 | 0 | int isneg; |
163 | |
|
164 | 0 | isneg = M_ISNEG(fpi); |
165 | 0 | if (isneg) { |
166 | 0 | M_NEG(fpi, fpf); |
167 | 0 | } |
168 | |
|
169 | 0 | return dolfptoa(fpi, fpf, (isneg?'-':'+'), ndec, TRUE); |
170 | 0 | } |
171 | | |
172 | | |