25
25
*/
26
26
27
27
#include "py/mpconfig.h"
28
+ #include "py/misc.h"
28
29
#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE
29
30
30
31
#include <assert.h>
@@ -96,7 +97,16 @@ static inline int fp_isless1(float x) {
96
97
#define fp_iszero (x ) (x == 0)
97
98
#define fp_isless1 (x ) (x < 1.0)
98
99
99
- #endif
100
+ #endif // MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT/DOUBLE
101
+
102
+ static inline int fp_ge_eps (FPTYPE x , FPTYPE y ) {
103
+ mp_float_union_t fb_y = {y };
104
+ // Back off 2 eps.
105
+ // This is valid for almost all values, but in practice
106
+ // it's only used when y = 1eX for X>=0.
107
+ fb_y .i -= 2 ;
108
+ return x >= fb_y .f ;
109
+ }
100
110
101
111
static const FPTYPE g_pos_pow [] = {
102
112
#if FPDECEXP > 32
@@ -173,6 +183,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
173
183
int num_digits = 0 ;
174
184
const FPTYPE * pos_pow = g_pos_pow ;
175
185
const FPTYPE * neg_pow = g_neg_pow ;
186
+ int signed_e = 0 ;
176
187
177
188
if (fp_iszero (f )) {
178
189
e = 0 ;
@@ -192,40 +203,32 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
192
203
}
193
204
}
194
205
} 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
-
206
+ FPTYPE f_mod = f ;
204
207
// Build negative exponent
205
208
for (e = 0 , e1 = FPDECEXP ; e1 ; e1 >>= 1 , pos_pow ++ , neg_pow ++ ) {
206
- if (* neg_pow > f ) {
209
+ if (* neg_pow > f_mod ) {
207
210
e += e1 ;
208
- f *= * pos_pow ;
211
+ f_mod *= * pos_pow ;
209
212
}
210
213
}
214
+
211
215
char e_sign_char = '-' ;
212
- if (fp_isless1 (f ) && f >= FPROUND_TO_ONE ) {
213
- f = FPCONST (1.0 );
216
+ if (fp_isless1 (f_mod ) && f_mod >= FPROUND_TO_ONE ) {
217
+ f_mod = FPCONST (1.0 );
214
218
if (e == 0 ) {
215
219
e_sign_char = '+' ;
216
220
}
217
- } else if (fp_isless1 (f )) {
221
+ } else if (fp_isless1 (f_mod )) {
218
222
e ++ ;
219
- f *= FPCONST (10.0 );
223
+ f_mod *= FPCONST (10.0 );
220
224
}
221
225
222
226
// If the user specified 'g' format, and e is <= 4, then we'll switch
223
227
// to the fixed format ('f')
224
228
225
229
if (fmt == 'f' || (fmt == 'g' && e <= 4 )) {
226
230
fmt = 'f' ;
227
- dec = -1 ;
228
- * s ++ = first_dig ;
231
+ dec = 0 ;
229
232
230
233
if (org_fmt == 'g' ) {
231
234
prec += (e - 1 );
@@ -237,13 +240,8 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
237
240
}
238
241
239
242
num_digits = prec ;
240
- if (num_digits ) {
241
- * s ++ = '.' ;
242
- while (-- e && num_digits ) {
243
- * s ++ = '0' ;
244
- num_digits -- ;
245
- }
246
- }
243
+ signed_e = 0 ;
244
+ ++ num_digits ;
247
245
} else {
248
246
// For e & g formats, we'll be printing the exponent, so set the
249
247
// sign.
@@ -256,22 +254,29 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
256
254
prec ++ ;
257
255
}
258
256
}
257
+ signed_e = - e ;
259
258
}
260
259
} else {
261
- // Build positive exponent
262
- for (e = 0 , e1 = FPDECEXP ; e1 ; e1 >>= 1 , pos_pow ++ , neg_pow ++ ) {
263
- if (* pos_pow <= f ) {
260
+ // Build positive exponent.
261
+ // We don't modify f at this point to avoid innaccuracies from
262
+ // scaling it. Instead, we find the product of powers of 10
263
+ // that is not greater than it, and use that to start the
264
+ // mantissa.
265
+ FPTYPE u_base = FPCONST (1.0 );
266
+ for (e = 0 , e1 = FPDECEXP ; e1 ; e1 >>= 1 , pos_pow ++ ) {
267
+ FPTYPE next_u = u_base * * pos_pow ;
268
+ // fp_ge_eps performs "f >= (next_u - 2eps)" so that if, for
269
+ // numerical reasons, f is very close to a power of ten but
270
+ // not strictly equal, we still treat it as that power of 10.
271
+ // The comparison was failing for maybe 10% of 1eX values, but
272
+ // although rounding fixed many of them, there were still some
273
+ // rendering as 9.99999998e(X-1).
274
+ if (fp_ge_eps (f , next_u )) {
275
+ u_base = next_u ;
264
276
e += e1 ;
265
- f *= * neg_pow ;
266
277
}
267
278
}
268
279
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
280
// If the user specified fixed format (fmt == 'f') and e makes the
276
281
// number too big to fit into the available buffer, then we'll
277
282
// switch to the 'e' format.
@@ -310,15 +315,15 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
310
315
} else {
311
316
e_sign = '+' ;
312
317
}
318
+ signed_e = e ;
313
319
}
314
320
if (prec < 0 ) {
315
321
// This can happen when the prec is trimmed to prevent buffer overflow
316
322
prec = 0 ;
317
323
}
318
324
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.
325
+ // At this point e contains the absolute value of the power of 10 exponent.
326
+ // (dec + 1) == the number of dgits before the decimal.
322
327
323
328
// For e, prec is # digits after the decimal
324
329
// For f, prec is # digits after the decimal
@@ -336,25 +341,63 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
336
341
num_digits = prec ;
337
342
}
338
343
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 {
344
+ if (signed_e < 0 ) {
345
+ // The algorithm below treats numbers smaller than 1 by scaling them
346
+ // repeatedly by 10 to bring the new digit to the top. Our input number
347
+ // was smaller than 1, so scale it up to be 1 <= f < 10.
348
+ FPTYPE u_base = FPCONST (1.0 );
349
+ const FPTYPE * pow_u = g_pos_pow ;
350
+ for (int m = FPDECEXP ; m ; m >>= 1 , pow_u ++ ) {
351
+ if (m & e ) {
352
+ u_base *= * pow_u ;
353
+ }
354
+ }
355
+ f *= u_base ;
356
+ }
357
+
358
+ int d = 0 ;
359
+ int num_digits_left = num_digits ;
360
+ for (int digit_index = signed_e ; num_digits_left >= 0 ; -- digit_index ) {
361
+ FPTYPE u_base = FPCONST (1.0 );
362
+ if (digit_index > 0 ) {
363
+ // Generate 10^digit_index for positive digit_index.
364
+ const FPTYPE * pow_u = g_pos_pow ;
365
+ int target_index = digit_index ;
366
+ for (int m = FPDECEXP ; m ; m >>= 1 , pow_u ++ ) {
367
+ if (m & target_index ) {
368
+ u_base *= * pow_u ;
369
+ }
370
+ }
371
+ }
372
+ for (d = 0 ; d < 9 ; ++ d ) {
373
+ // This is essentially "if (f < u_base)", but with 2eps margin
374
+ // so that if f is just a tiny bit smaller, we treat it as
375
+ // equal (and accept the additional digit value).
376
+ if (!fp_ge_eps (f , u_base )) {
377
+ break ;
378
+ }
379
+ f -= u_base ;
380
+ }
381
+ // We calculate one more digit than we display, to use in rounding
382
+ // below. So only emit the digit if it's one that we display.
383
+ if (num_digits_left > 0 ) {
384
+ // Emit this number (the leading digit).
345
385
* s ++ = '0' + d ;
386
+ if (dec == 0 && prec > 0 ) {
387
+ * s ++ = '.' ;
388
+ }
346
389
}
347
- if (dec == 0 && prec > 0 ) {
348
- * s ++ = '.' ;
390
+ -- dec ;
391
+ -- num_digits_left ;
392
+ if (digit_index <= 0 ) {
393
+ // Once we get below 1.0, we scale up f instead of calculting
394
+ // negative powers of 10 in u_base. This provides better
395
+ // renditions of exact decimals like 1/16 etc.
396
+ f *= FPCONST (10.0 );
349
397
}
350
- f -= (FPTYPE )d ;
351
- f *= FPCONST (10.0 );
352
398
}
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 )) {
399
+ // Rounding. If the next digit to print is >= 5, round up.
400
+ if (d >= 5 ) {
358
401
char * rs = s ;
359
402
rs -- ;
360
403
while (1 ) {
@@ -394,7 +437,10 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
394
437
}
395
438
} else {
396
439
// Need at extra digit at the end to make room for the leading '1'
397
- s ++ ;
440
+ // but if we're at the buffer size limit, just drop the final digit.
441
+ if ((size_t )(s + 1 - buf ) < buf_size ) {
442
+ s ++ ;
443
+ }
398
444
}
399
445
char * ss = s ;
400
446
while (ss > rs ) {
0 commit comments