blob: e42266a714928a67860996f9c466f841f866001d [file] [log] [blame]
Damien George8bfec2b2014-03-10 13:27:02 +00001/***********************************************************************
2
3 formatfloat.c - Ruutine for converting a single-precision floating
Dave Hylandsca5a2412014-03-10 00:10:01 -07004 point number into a string.
Damien George8bfec2b2014-03-10 13:27:02 +00005
Dave Hylandsca5a2412014-03-10 00:10:01 -07006 The code in this funcion was inspired from Fred Bayer's pdouble.c.
7 Since pdouble.c was released as Public Domain, I'm releasing this
8 code as public domain as well.
Damien George8bfec2b2014-03-10 13:27:02 +00009
Dave Hylandsca5a2412014-03-10 00:10:01 -070010 The original code can be found in https://github.com/dhylands/format-float
Damien George8bfec2b2014-03-10 13:27:02 +000011
Dave Hylandsca5a2412014-03-10 00:10:01 -070012 Dave Hylands
Damien George8bfec2b2014-03-10 13:27:02 +000013
Dave Hylandsca5a2412014-03-10 00:10:01 -070014***********************************************************************/
15
Damien George8bfec2b2014-03-10 13:27:02 +000016#include <stdint.h>
Dave Hylandsca5a2412014-03-10 00:10:01 -070017#include <stdlib.h>
18
19#include "mpconfig.h"
20
21#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
Damien George8bfec2b2014-03-10 13:27:02 +000022#include "formatfloat.h"
Dave Hylandsca5a2412014-03-10 00:10:01 -070023
24// 1 sign bit, 8 exponent bits, and 23 mantissa bits.
25// exponent values 0 and 255 are reserved, exponent can be 1 to 254.
26// exponent is stored with a bias of 127.
27// The min and max floats are on the order of 1x10^37 and 1x10^-37
28
29#define FLT_SIGN_MASK 0x80000000
30#define FLT_EXP_MASK 0x7F800000
31#define FLT_MAN_MASK 0x007FFFFF
32
33static const float g_pos_pow[] = {
34 1e32, 1e16, 1e8, 1e4, 1e2, 1e1
35};
36static const float g_neg_pow[] = {
37 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
38};
39
40int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
41
42 char *s = buf;
43 int buf_remaining = buf_size - 1;
44
45 union {
46 float f;
47 uint32_t u;
48 } num = {f};
49
50 if (buf_size < 7) {
51 // Smallest exp notion is -9e+99 which is 6 chars plus terminating
52 // nulll.
53
54 if (buf_size >= 2) {
55 *s++ = '?';
56 }
57 if (buf_size >= 1) {
58 *s++ = '\0';
59 }
60 return buf_size >= 2;
61 }
62 if (num.u & FLT_SIGN_MASK) {
63 *s++ = '-';
64 num.u &= ~FLT_SIGN_MASK;
65 } else {
66 if (sign) {
67 *s++ = sign;
68 }
69 }
70 buf_remaining -= (s - buf); // Adjust for sign
71
72 if ((num.u & FLT_EXP_MASK) == FLT_EXP_MASK) {
73 char uc = fmt & 0x20;
74 if ((num.u & FLT_MAN_MASK) == 0) {
75 *s++ = 'I' ^ uc;
76 *s++ = 'N' ^ uc;
77 *s++ = 'F' ^ uc;
78 } else {
79 *s++ = 'N' ^ uc;
80 *s++ = 'A' ^ uc;
81 *s++ = 'N' ^ uc;
82 }
83 *s = '\0';
84 return s - buf;
85 }
86
87 if (prec < 0) {
88 prec = 6;
89 }
90 char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt
91 fmt |= 0x20; // Force fmt to be lowercase
92 char org_fmt = fmt;
93 if (fmt == 'g' && prec == 0) {
94 prec = 1;
95 }
96 int e, e1;
97 int dec = 0;
98 char e_sign = '\0';
99 int num_digits = 0;
100 const float *pos_pow = g_pos_pow;
101 const float *neg_pow = g_neg_pow;
102
103 if (num.u == 0) {
104 e = 0;
105 if (fmt == 'e') {
106 e_sign = '+';
107 } else if (fmt == 'f') {
108 num_digits = prec + 1;
109 }
110 } else if (num.u < 0x3f800000) { // f < 1.0
111 // Build negative exponent
112 for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) {
113 if (*neg_pow > num.f) {
114 e += e1;
115 num.f *= *pos_pow;
116 }
117 }
118 if (num.f < 1.0F && num.f >= 0.9999995F) {
119 num.f = 1.0F;
120 } else {
121 e++;
122 num.f *= 10.0F;
123 }
124
125 // If the user specified 'g' format, and e is <= 4, then we'll switch
126 // to the fixed format ('f')
127
128 if (fmt == 'f' || (fmt == 'g' && e <= 4)) {
129 fmt = 'f';
130 dec = -1;
131 *s++ = '0';
132
133 if (prec + e + 1 > buf_remaining) {
134 prec = buf_remaining - e - 1;
135 }
136
137 if (org_fmt == 'g') {
138 prec += (e - 1);
139 }
140 num_digits = prec;
141 if (num_digits) {
142 *s++ = '.';
143 while (--e && num_digits) {
144 *s++ = '0';
145 num_digits--;
146 }
147 }
148 } else {
149 // For e & g formats, we'll be printing the exponent, so set the
150 // sign.
151 e_sign = '-';
152 dec = 0;
153
154 if (prec > (buf_remaining - 6)) {
155 prec = buf_remaining - 6;
156 if (fmt == 'g') {
157 prec++;
158 }
159 }
160 }
161 } else {
162 // Build positive exponent
163 for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) {
164 if (*pos_pow <= num.f) {
165 e += e1;
166 num.f *= *neg_pow;
167 }
168 }
169
170 // If the user specified fixed format (fmt == 'f') and e makes the
171 // number too big to fit into the available buffer, then we'll
172 // switch to the 'e' format.
173
174 if (fmt == 'f') {
175 if (e >= buf_remaining) {
176 fmt = 'e';
177 } else if ((e + prec + 2) > buf_remaining) {
178 prec = buf_remaining - e - 2;
179 if (prec < 0) {
180 // This means no decimal point, so we can add one back
181 // for the decimal.
182 prec++;
183 }
184 }
185 }
186 if (fmt == 'e' && prec > (buf_remaining - 6)) {
187 prec = buf_remaining - 6;
188 }
189 // If the user specified 'g' format, and e is < prec, then we'll switch
190 // to the fixed format.
191
192 if (fmt == 'g' && e < prec) {
193 fmt = 'f';
194 prec -= (e + 1);
195 }
196 if (fmt == 'f') {
197 dec = e;
198 num_digits = prec + e + 1;
199 } else {
200 e_sign = '+';
201 }
202 }
203 if (prec < 0) {
204 // This can happen when the prec is trimmed to prevent buffer overflow
205 prec = 0;
206 }
207
208 // We now have num.f as a floating point number between >= 1 and < 10
209 // (or equal to zero), and e contains the absolute value of the power of
210 // 10 exponent. and (dec + 1) == the number of dgits before the decimal.
211
212 // For e, prec is # digits after the decimal
213 // For f, prec is # digits after the decimal
214 // For g, prec is the max number of significant digits
215 //
216 // For e & g there will be a single digit before the decimal
217 // for f there will be e digits before the decimal
218
219 if (fmt == 'e') {
220 num_digits = prec + 1;
221 } else if (fmt == 'g') {
222 if (prec == 0) {
223 prec = 1;
224 }
225 num_digits = prec;
226 }
227
228 // Print the digits of the mantissa
229 for (int i = 0; i < num_digits; ++i, --dec) {
230 int32_t d = num.f;
231 *s++ = '0' + d;
232 if (dec == 0 && prec > 0) {
233 *s++ = '.';
234 }
235 num.f -= (float)d;
236 num.f *= 10.0F;
237 }
238
239 // Round
240 if (num.f >= 5.0F) {
241 char *rs = s;
242 rs--;
243 while (1) {
244 if (*rs == '.') {
245 rs--;
246 continue;
247 }
248 if (*rs < '0' || *rs > '9') {
249 // + or -
250 rs++; // So we sit on the digit to the right of the sign
251 break;
252 }
253 if (*rs < '9') {
254 (*rs)++;
255 break;
256 }
257 *rs = '0';
258 if (rs == buf) {
259 break;
260 }
261 rs--;
262 }
263 if (*rs == '0') {
264 // We need to insert a 1
265 if (rs[1] == '.' && fmt != 'f') {
266 // We're going to round 9.99 to 10.00
267 // Move the decimal point
268 rs[0] = '.';
269 rs[1] = '0';
270 if (e_sign == '-') {
271 e--;
272 } else {
273 e++;
274 }
275 }
276 s++;
277 char *ss = s;
278 while (ss > rs) {
279 *ss = ss[-1];
280 ss--;
281 }
282 *rs = '1';
283 }
284 if (num.u < 0x3f800000 && fmt == 'f') {
285 // We rounded up to 1.0
286 prec--;
287 }
288 }
289
290 if (org_fmt == 'g' && prec > 0) {
291 // Remove trailing zeros and a trailing decimal point
292 while (s[-1] == '0') {
293 s--;
294 }
295 if (s[-1] == '.') {
296 s--;
297 }
298 }
299 // Append the exponent
300 if (e_sign) {
301 *s++ = e_char;
302 *s++ = e_sign;
303 *s++ = '0' + (e / 10);
304 *s++ = '0' + (e % 10);
305 }
306 *s = '\0';
307
308 return s - buf;
309}
310
311#endif