1 | /* |
2 | * This file is part of the MicroPython project, http://micropython.org/ |
3 | * |
4 | * The MIT License (MIT) |
5 | * |
6 | * Copyright (c) 2013, 2014 Damien P. George |
7 | * |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | * of this software and associated documentation files (the "Software"), to deal |
10 | * in the Software without restriction, including without limitation the rights |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | * copies of the Software, and to permit persons to whom the Software is |
13 | * furnished to do so, subject to the following conditions: |
14 | * |
15 | * The above copyright notice and this permission notice shall be included in |
16 | * all copies or substantial portions of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
24 | * THE SOFTWARE. |
25 | */ |
26 | |
27 | #include "py/mpconfig.h" |
28 | #if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE |
29 | |
30 | #include <assert.h> |
31 | #include <stdlib.h> |
32 | #include <stdint.h> |
33 | #include <math.h> |
34 | #include "py/formatfloat.h" |
35 | |
36 | /*********************************************************************** |
37 | |
38 | Routine for converting a arbitrary floating |
39 | point number into a string. |
40 | |
41 | The code in this funcion was inspired from Fred Bayer's pdouble.c. |
42 | Since pdouble.c was released as Public Domain, I'm releasing this |
43 | code as public domain as well. |
44 | |
45 | The original code can be found in https://github.com/dhylands/format-float |
46 | |
47 | Dave Hylands |
48 | |
49 | ***********************************************************************/ |
50 | |
51 | #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT |
52 | // 1 sign bit, 8 exponent bits, and 23 mantissa bits. |
53 | // exponent values 0 and 255 are reserved, exponent can be 1 to 254. |
54 | // exponent is stored with a bias of 127. |
55 | // The min and max floats are on the order of 1x10^37 and 1x10^-37 |
56 | |
57 | #define FPTYPE float |
58 | #define FPCONST(x) x##F |
59 | #define FPROUND_TO_ONE 0.9999995F |
60 | #define FPDECEXP 32 |
61 | #define FPMIN_BUF_SIZE 6 // +9e+99 |
62 | |
63 | #define FLT_SIGN_MASK 0x80000000 |
64 | #define FLT_EXP_MASK 0x7F800000 |
65 | #define FLT_MAN_MASK 0x007FFFFF |
66 | |
67 | union floatbits { |
68 | float f; |
69 | uint32_t u; |
70 | }; |
71 | static inline int fp_signbit(float x) { |
72 | union floatbits fb = {x}; |
73 | return fb.u & FLT_SIGN_MASK; |
74 | } |
75 | #define fp_isnan(x) isnan(x) |
76 | #define fp_isinf(x) isinf(x) |
77 | static inline int fp_iszero(float x) { |
78 | union floatbits fb = {x}; |
79 | return fb.u == 0; |
80 | } |
81 | static inline int fp_isless1(float x) { |
82 | union floatbits fb = {x}; |
83 | return fb.u < 0x3f800000; |
84 | } |
85 | |
86 | #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE |
87 | |
88 | #define FPTYPE double |
89 | #define FPCONST(x) x |
90 | #define FPROUND_TO_ONE 0.999999999995 |
91 | #define FPDECEXP 256 |
92 | #define FPMIN_BUF_SIZE 7 // +9e+199 |
93 | #define fp_signbit(x) signbit(x) |
94 | #define fp_isnan(x) isnan(x) |
95 | #define fp_isinf(x) isinf(x) |
96 | #define fp_iszero(x) (x == 0) |
97 | #define fp_isless1(x) (x < 1.0) |
98 | |
99 | #endif |
100 | |
101 | static const FPTYPE g_pos_pow[] = { |
102 | #if FPDECEXP > 32 |
103 | MICROPY_FLOAT_CONST(1e256), MICROPY_FLOAT_CONST(1e128), MICROPY_FLOAT_CONST(1e64), |
104 | #endif |
105 | MICROPY_FLOAT_CONST(1e32), MICROPY_FLOAT_CONST(1e16), MICROPY_FLOAT_CONST(1e8), MICROPY_FLOAT_CONST(1e4), MICROPY_FLOAT_CONST(1e2), MICROPY_FLOAT_CONST(1e1) |
106 | }; |
107 | static const FPTYPE g_neg_pow[] = { |
108 | #if FPDECEXP > 32 |
109 | MICROPY_FLOAT_CONST(1e-256), MICROPY_FLOAT_CONST(1e-128), MICROPY_FLOAT_CONST(1e-64), |
110 | #endif |
111 | MICROPY_FLOAT_CONST(1e-32), MICROPY_FLOAT_CONST(1e-16), MICROPY_FLOAT_CONST(1e-8), MICROPY_FLOAT_CONST(1e-4), MICROPY_FLOAT_CONST(1e-2), MICROPY_FLOAT_CONST(1e-1) |
112 | }; |
113 | |
114 | int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) { |
115 | |
116 | char *s = buf; |
117 | |
118 | if (buf_size <= FPMIN_BUF_SIZE) { |
119 | // FPMIN_BUF_SIZE is the minimum size needed to store any FP number. |
120 | // If the buffer does not have enough room for this (plus null terminator) |
121 | // then don't try to format the float. |
122 | |
123 | if (buf_size >= 2) { |
124 | *s++ = '?'; |
125 | } |
126 | if (buf_size >= 1) { |
127 | *s = '\0'; |
128 | } |
129 | return buf_size >= 2; |
130 | } |
131 | if (fp_signbit(f) && !fp_isnan(f)) { |
132 | *s++ = '-'; |
133 | f = -f; |
134 | } else { |
135 | if (sign) { |
136 | *s++ = sign; |
137 | } |
138 | } |
139 | |
140 | // buf_remaining contains bytes available for digits and exponent. |
141 | // It is buf_size minus room for the sign and null byte. |
142 | int buf_remaining = buf_size - 1 - (s - buf); |
143 | |
144 | { |
145 | char uc = fmt & 0x20; |
146 | if (fp_isinf(f)) { |
147 | *s++ = 'I' ^ uc; |
148 | *s++ = 'N' ^ uc; |
149 | *s++ = 'F' ^ uc; |
150 | goto ret; |
151 | } else if (fp_isnan(f)) { |
152 | *s++ = 'N' ^ uc; |
153 | *s++ = 'A' ^ uc; |
154 | *s++ = 'N' ^ uc; |
155 | ret: |
156 | *s = '\0'; |
157 | return s - buf; |
158 | } |
159 | } |
160 | |
161 | if (prec < 0) { |
162 | prec = 6; |
163 | } |
164 | char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt |
165 | fmt |= 0x20; // Force fmt to be lowercase |
166 | char org_fmt = fmt; |
167 | if (fmt == 'g' && prec == 0) { |
168 | prec = 1; |
169 | } |
170 | int e, e1; |
171 | int dec = 0; |
172 | char e_sign = '\0'; |
173 | int num_digits = 0; |
174 | const FPTYPE *pos_pow = g_pos_pow; |
175 | const FPTYPE *neg_pow = g_neg_pow; |
176 | |
177 | if (fp_iszero(f)) { |
178 | e = 0; |
179 | if (fmt == 'f') { |
180 | // Truncate precision to prevent buffer overflow |
181 | if (prec + 2 > buf_remaining) { |
182 | prec = buf_remaining - 2; |
183 | } |
184 | num_digits = prec + 1; |
185 | } else { |
186 | // Truncate precision to prevent buffer overflow |
187 | if (prec + 6 > buf_remaining) { |
188 | prec = buf_remaining - 6; |
189 | } |
190 | if (fmt == 'e') { |
191 | e_sign = '+'; |
192 | } |
193 | } |
194 | } else if (fp_isless1(f)) { |
195 | // We need to figure out what an integer digit will be used |
196 | // in case 'f' is used (or we revert other format to it below). |
197 | // As we just tested number to be <1, this is obviously 0, |
198 | // but we can round it up to 1 below. |
199 | char first_dig = '0'; |
200 | if (f >= FPROUND_TO_ONE) { |
201 | first_dig = '1'; |
202 | } |
203 | |
204 | // Build negative exponent |
205 | for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { |
206 | if (*neg_pow > f) { |
207 | e += e1; |
208 | f *= *pos_pow; |
209 | } |
210 | } |
211 | char e_sign_char = '-'; |
212 | if (fp_isless1(f) && f >= FPROUND_TO_ONE) { |
213 | f = FPCONST(1.0); |
214 | if (e == 0) { |
215 | e_sign_char = '+'; |
216 | } |
217 | } else if (fp_isless1(f)) { |
218 | e++; |
219 | f *= FPCONST(10.0); |
220 | } |
221 | |
222 | // If the user specified 'g' format, and e is <= 4, then we'll switch |
223 | // to the fixed format ('f') |
224 | |
225 | if (fmt == 'f' || (fmt == 'g' && e <= 4)) { |
226 | fmt = 'f'; |
227 | dec = -1; |
228 | *s++ = first_dig; |
229 | |
230 | if (org_fmt == 'g') { |
231 | prec += (e - 1); |
232 | } |
233 | |
234 | // truncate precision to prevent buffer overflow |
235 | if (prec + 2 > buf_remaining) { |
236 | prec = buf_remaining - 2; |
237 | } |
238 | |
239 | num_digits = prec; |
240 | if (num_digits) { |
241 | *s++ = '.'; |
242 | while (--e && num_digits) { |
243 | *s++ = '0'; |
244 | num_digits--; |
245 | } |
246 | } |
247 | } else { |
248 | // For e & g formats, we'll be printing the exponent, so set the |
249 | // sign. |
250 | e_sign = e_sign_char; |
251 | dec = 0; |
252 | |
253 | if (prec > (buf_remaining - FPMIN_BUF_SIZE)) { |
254 | prec = buf_remaining - FPMIN_BUF_SIZE; |
255 | if (fmt == 'g') { |
256 | prec++; |
257 | } |
258 | } |
259 | } |
260 | } else { |
261 | // Build positive exponent |
262 | for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { |
263 | if (*pos_pow <= f) { |
264 | e += e1; |
265 | f *= *neg_pow; |
266 | } |
267 | } |
268 | |
269 | // It can be that f was right on the edge of an entry in pos_pow needs to be reduced |
270 | if ((int)f >= 10) { |
271 | e += 1; |
272 | f *= FPCONST(0.1); |
273 | } |
274 | |
275 | // If the user specified fixed format (fmt == 'f') and e makes the |
276 | // number too big to fit into the available buffer, then we'll |
277 | // switch to the 'e' format. |
278 | |
279 | if (fmt == 'f') { |
280 | if (e >= buf_remaining) { |
281 | fmt = 'e'; |
282 | } else if ((e + prec + 2) > buf_remaining) { |
283 | prec = buf_remaining - e - 2; |
284 | if (prec < 0) { |
285 | // This means no decimal point, so we can add one back |
286 | // for the decimal. |
287 | prec++; |
288 | } |
289 | } |
290 | } |
291 | if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) { |
292 | prec = buf_remaining - FPMIN_BUF_SIZE; |
293 | } |
294 | if (fmt == 'g') { |
295 | // Truncate precision to prevent buffer overflow |
296 | if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) { |
297 | prec = buf_remaining - (FPMIN_BUF_SIZE - 1); |
298 | } |
299 | } |
300 | // If the user specified 'g' format, and e is < prec, then we'll switch |
301 | // to the fixed format. |
302 | |
303 | if (fmt == 'g' && e < prec) { |
304 | fmt = 'f'; |
305 | prec -= (e + 1); |
306 | } |
307 | if (fmt == 'f') { |
308 | dec = e; |
309 | num_digits = prec + e + 1; |
310 | } else { |
311 | e_sign = '+'; |
312 | } |
313 | } |
314 | if (prec < 0) { |
315 | // This can happen when the prec is trimmed to prevent buffer overflow |
316 | prec = 0; |
317 | } |
318 | |
319 | // We now have num.f as a floating point number between >= 1 and < 10 |
320 | // (or equal to zero), and e contains the absolute value of the power of |
321 | // 10 exponent. and (dec + 1) == the number of dgits before the decimal. |
322 | |
323 | // For e, prec is # digits after the decimal |
324 | // For f, prec is # digits after the decimal |
325 | // For g, prec is the max number of significant digits |
326 | // |
327 | // For e & g there will be a single digit before the decimal |
328 | // for f there will be e digits before the decimal |
329 | |
330 | if (fmt == 'e') { |
331 | num_digits = prec + 1; |
332 | } else if (fmt == 'g') { |
333 | if (prec == 0) { |
334 | prec = 1; |
335 | } |
336 | num_digits = prec; |
337 | } |
338 | |
339 | // Print the digits of the mantissa |
340 | for (int i = 0; i < num_digits; ++i, --dec) { |
341 | int32_t d = (int32_t)f; |
342 | if (d < 0) { |
343 | *s++ = '0'; |
344 | } else { |
345 | *s++ = '0' + d; |
346 | } |
347 | if (dec == 0 && prec > 0) { |
348 | *s++ = '.'; |
349 | } |
350 | f -= (FPTYPE)d; |
351 | f *= FPCONST(10.0); |
352 | } |
353 | |
354 | // Round |
355 | // If we print non-exponential format (i.e. 'f'), but a digit we're going |
356 | // to round by (e) is too far away, then there's nothing to round. |
357 | if ((org_fmt != 'f' || e <= num_digits) && f >= FPCONST(5.0)) { |
358 | char *rs = s; |
359 | rs--; |
360 | while (1) { |
361 | if (*rs == '.') { |
362 | rs--; |
363 | continue; |
364 | } |
365 | if (*rs < '0' || *rs > '9') { |
366 | // + or - |
367 | rs++; // So we sit on the digit to the right of the sign |
368 | break; |
369 | } |
370 | if (*rs < '9') { |
371 | (*rs)++; |
372 | break; |
373 | } |
374 | *rs = '0'; |
375 | if (rs == buf) { |
376 | break; |
377 | } |
378 | rs--; |
379 | } |
380 | if (*rs == '0') { |
381 | // We need to insert a 1 |
382 | if (rs[1] == '.' && fmt != 'f') { |
383 | // We're going to round 9.99 to 10.00 |
384 | // Move the decimal point |
385 | rs[0] = '.'; |
386 | rs[1] = '0'; |
387 | if (e_sign == '-') { |
388 | e--; |
389 | if (e == 0) { |
390 | e_sign = '+'; |
391 | } |
392 | } else { |
393 | e++; |
394 | } |
395 | } else { |
396 | // Need at extra digit at the end to make room for the leading '1' |
397 | s++; |
398 | } |
399 | char *ss = s; |
400 | while (ss > rs) { |
401 | *ss = ss[-1]; |
402 | ss--; |
403 | } |
404 | *rs = '1'; |
405 | } |
406 | } |
407 | |
408 | // verify that we did not overrun the input buffer so far |
409 | assert((size_t)(s + 1 - buf) <= buf_size); |
410 | |
411 | if (org_fmt == 'g' && prec > 0) { |
412 | // Remove trailing zeros and a trailing decimal point |
413 | while (s[-1] == '0') { |
414 | s--; |
415 | } |
416 | if (s[-1] == '.') { |
417 | s--; |
418 | } |
419 | } |
420 | // Append the exponent |
421 | if (e_sign) { |
422 | *s++ = e_char; |
423 | *s++ = e_sign; |
424 | if (FPMIN_BUF_SIZE == 7 && e >= 100) { |
425 | *s++ = '0' + (e / 100); |
426 | } |
427 | *s++ = '0' + ((e / 10) % 10); |
428 | *s++ = '0' + (e % 10); |
429 | } |
430 | *s = '\0'; |
431 | |
432 | // verify that we did not overrun the input buffer |
433 | assert((size_t)(s + 1 - buf) <= buf_size); |
434 | |
435 | return s - buf; |
436 | } |
437 | |
438 | #endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE |
439 | |