1 /* Copyright (c) 2005, Dmitry Xmelkov
2 All rights reserved.
3 Rewritten in C by Soren Kuula
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in
10 the documentation and/or other materials provided with the
11 distribution.
12 * Neither the name of the copyright holders nor the names of
13 contributors may be used to endorse or promote products derived
14 from this software without specific prior written permission.
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 POSSIBILITY OF SUCH DAMAGE. */
26
27 #include "ftoa_engine.h"
28 #include <stdint.h>
29
30 /*
31 * 2^b ~= f * r * 10^e
32 * where
33 * i = b div 8
34 * r = 2^(b mod 8)
35 * f = factorTable[i]
36 * e = exponentTable[i]
37 */
38 static const int8_t exponentTable[32] = {
39 -36, -33, -31, -29, -26, -24, -21, -19,
40 -17, -14, -12, -9, -7, -4, -2, 0,
41 3, 5, 8, 10, 12, 15, 17, 20,
42 22, 24, 27, 29, 32, 34, 36, 39
43 };
44
45 static const uint32_t factorTable[32] = {
46 2295887404UL,
47 587747175UL,
48 1504632769UL,
49 3851859889UL,
50 986076132UL,
51 2524354897UL,
52 646234854UL,
53 1654361225UL,
54 4235164736UL,
55 1084202172UL,
56 2775557562UL,
57 710542736UL,
58 1818989404UL,
59 465661287UL,
60 1192092896UL,
61 3051757813UL,
62 781250000UL,
63 2000000000UL,
64 512000000UL,
65 1310720000UL,
66 3355443200UL,
67 858993459UL,
68 2199023256UL,
69 562949953UL,
70 1441151881UL,
71 3689348815UL,
72 944473297UL,
73 2417851639UL,
74 618970020UL,
75 1584563250UL,
76 4056481921UL,
77 1038459372UL
78 };
79
80 #define max(a, b) ({\
81 __typeof(a) _a = a;\
82 __typeof(b) _b = b;\
83 _a > _b ? _a : _b; })
84
85 #define min(a, b) ({\
86 __typeof(a) _a = a;\
87 __typeof(b) _b = b;\
88 _a < _b ? _a : _b; })
89
__ftoa_engine(float val,struct ftoa * ftoa,int maxDigits,bool fmode,int maxDecimals)90 int __ftoa_engine(float val, struct ftoa *ftoa, int maxDigits, bool fmode, int maxDecimals)
91 {
92 uint8_t flags = 0;
93
94 union {
95 float v;
96 uint32_t u;
97 } x;
98
99 x.v = val;
100
101 uint32_t frac = x.u & 0x007fffffUL;
102
103 if (maxDigits > FTOA_MAX_DIG)
104 maxDigits = FTOA_MAX_DIG;
105
106 /* Read the sign, shift the exponent in place and delete it from frac.
107 */
108 if (x.u & ((uint32_t)1 << 31))
109 flags = FTOA_MINUS;
110
111 uint8_t exp = x.u >> 23;
112
113 ftoa->exp = 0;
114
115 /*
116 * Test for easy cases, zero and NaN
117 */
118 if(exp==0 && frac==0)
119 {
120 flags |= FTOA_ZERO;
121 ftoa->digits[0] = '0';
122 maxDigits = 1;
123 } else if(exp == 0xff) {
124 if(frac == 0)
125 flags |= FTOA_INF;
126 else
127 flags |= FTOA_NAN;
128 } else {
129
130 /* The implicit leading 1 is made explicit, except if value
131 * subnormal, in which case exp needs to be adjusted by one
132 */
133 if (exp == 0)
134 exp = 1;
135 else
136 frac |= (1UL<<23);
137
138 uint8_t idx = exp>>3;
139 int8_t exp10 = exponentTable[idx];
140
141 /*
142 * We COULD try making the multiplication in situ, where we make
143 * frac and a 64 bit int overlap in memory and select/weigh the
144 * upper 32 bits that way. For starters, this is less risky:
145 */
146 int64_t prod = (int64_t)frac * (int64_t)factorTable[idx];
147
148 /*
149 * The expConvFactorTable are factor are correct iff the lower 3 exponent
150 * bits are 1 (=7). Else we need to compensate by divding frac.
151 * If the lower 3 bits are 7 we are right.
152 * If the lower 3 bits are 6 we right-shift once
153 * ..
154 * If the lower 3 bits are 0 we right-shift 7x
155 */
156 prod >>= (15-(exp & 7));
157
158 /*
159 * Now convert to decimal.
160 */
161
162 uint8_t hadNonzeroDigit = 0; /* have seen a non-zero digit flag */
163 uint8_t outputIdx = 0;
164 int64_t decimal = 100000000000000ull;
165 uint8_t saveMaxDigits = maxDigits;
166
167 do {
168 /* Compute next digit */
169 char digit = prod / decimal + '0';
170
171 if(!hadNonzeroDigit)
172 {
173 /* Don't return results with a leading zero! Instead
174 * skip those and decrement exp10 accordingly.
175 */
176 if (digit == '0') {
177 exp10--;
178 prod = prod % decimal;
179 decimal /= 10;
180 continue;
181 }
182
183 /* Found the first non-zero digit */
184 hadNonzeroDigit = 1;
185
186 /* If limiting decimals... */
187 if(fmode)
188 {
189 maxDigits = min(maxDigits, max(1, maxDecimals + exp10 + 1));
190 if (maxDigits == 0)
191 break;
192 }
193 }
194 prod = prod % decimal;
195 decimal /= 10;
196
197 /* Now we have a digit. */
198 if(digit < '0' + 10) {
199 /* normal case. */
200 ftoa->digits[outputIdx] = digit;
201 } else {
202 /*
203 * Uh, oh. Something went wrong with our conversion. Write
204 * 9s and use the round-up code to report back to the caller
205 * that we've carried
206 */
207 for(outputIdx = 0; outputIdx < maxDigits; outputIdx++)
208 ftoa->digits[outputIdx] = '9';
209 goto round_up;
210 }
211 outputIdx++;
212 } while (outputIdx<maxDigits);
213
214 /* Rounding: */
215 decimal *= 10;
216 if (prod - (decimal >> 1) >= 0)
217 {
218 uint8_t rounded;
219 round_up:
220
221 rounded = 0;
222 while(outputIdx != 0) {
223
224 /* Increment digit, check if we're done */
225 if(++ftoa->digits[outputIdx-1] < '0' + 10) {
226 rounded = 1;
227 break;
228 }
229
230 ftoa->digits[--outputIdx] = '0';
231 /* and the loop continues, carrying to next digit. */
232 }
233
234 if (!rounded) {
235
236 /* Rounded past the first digit;
237 * reset the leading digit to 1,
238 * bump exp and tell the caller we've carried.
239 * The remaining digits will already be '0',
240 * so we don't need to mess with them
241 */
242 ftoa->digits[0] = '1';
243 exp10++;
244 if (fmode)
245 maxDigits = min(saveMaxDigits, max(1, maxDecimals + exp10 + 1));
246 flags |= FTOA_CARRY;
247 }
248 }
249 ftoa->exp = exp10;
250 }
251 ftoa->flags = flags;
252 ftoa->digits[maxDigits] = '\0';
253 return maxDigits;
254 }
255