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