@@ -174,7 +174,9 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
174
174
int num_digits = 0 ;
175
175
const FPTYPE * pos_pow = g_pos_pow ;
176
176
const FPTYPE * neg_pow = g_neg_pow ;
177
-
177
+ uint32_t f_int = 0 ;
178
+ uint32_t u_int = 0 ;
179
+
178
180
if (fp_iszero (f )) {
179
181
e = 0 ;
180
182
if (fmt == 'f' ) {
@@ -261,31 +263,40 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
261
263
} else {
262
264
// Build positive exponent
263
265
264
- // First block is only for numbers that could be integers exactly-represented in float32.
265
- if (f < FPCONST (1e10 )) {
266
- // In this case, we *won't* normalize f down to lie in 1 <= f < 10 because the
267
- // repeated scaling by 0.1 cumulates errors in the representation, meaning numbers
268
- // that start as integers become non-integers. Instead, we find the scale by
269
- // increasing a reference value through repeated multiplications by 10. This
270
- // whole number in the range 1e0..1e10 will be exactly represented.
271
- FPTYPE cumulated_power = FPCONST (1.0 );
272
- for (e = 0 , e1 = FPDECEXP ; e1 ; e1 >>= 1 , pos_pow ++ ) {
273
- if ((cumulated_power * * pos_pow ) <= f ) {
274
- e += e1 ;
275
- cumulated_power *= * pos_pow ;
276
- }
266
+ // First block is only for numbers that could be integers
267
+ // exactly-represented in float32. We handle the integer part
268
+ // by casting into a uint32_t, so exclude numbers larger than that
269
+ // limit (2^32, which is much larger than the 2^24 that is fully
270
+ // represented in a float32).
271
+ if (f < FPCONST (4294967296.0 )) { // 2^32
272
+ // In this case, we *won't* normalize f down to lie in 1 <= f < 10
273
+ // because the repeated scaling by 0.1 cumulates errors in the
274
+ // representation, meaning numbers that start as integers become
275
+ // non-integers. Instead, we work in the integer domain and find
276
+ // the scale by increasing a reference value through repeated
277
+ // (integer) multiplications by 10.
278
+ f_int = (uint32_t )f ;
279
+ u_int = 1 ;
280
+ e = 0 ;
281
+ while ((u_int * 10L ) <= f_int ) {
282
+ u_int *= 10L ;
283
+ ++ e ;
277
284
}
278
- // f is NOT normalized to be 1 <= f < 10; the mantissa printing is modified
279
- // to handle this.
285
+ // Note: u_int == 10**e is re-used in the mantissa printing below.
286
+
287
+ // f is NOT normalized to be 1 <= f < 10; the mantissa printing is
288
+ // modified to handle this.
280
289
} else {
281
- // Calculate the exponent and normalize f to lie in the range 1 <= f < 10.
290
+ // Calculate the exponent and normalize f to lie in the range
291
+ // 1 <= f < 10.
282
292
for (e = 0 , e1 = FPDECEXP ; e1 ; e1 >>= 1 , pos_pow ++ , neg_pow ++ ) {
283
293
if (* pos_pow <= f ) {
284
294
e += e1 ;
285
295
f *= * neg_pow ;
286
296
}
287
297
}
288
- // It can be that f was right on the edge of an entry in pos_pow needs to be reduced
298
+ // It can be that f was right on the edge of an entry in pos_pow
299
+ // needs to be reduced
289
300
if ((int )f >= 10 ) {
290
301
e += 1 ;
291
302
f *= FPCONST (0.1 );
@@ -341,9 +352,9 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
341
352
// before the decimal.
342
353
//
343
354
// For numbers in the range 1e1 to 1e10 (which includes all whole-values
344
- // that can be exactly represented in float32s), we do NOT normalize f
345
- // to avoid the small departures from whole numbers the scaling would
346
- // incur.
355
+ // that can be exactly, continuously represented in float32s), we do NOT
356
+ // normalize f, to avoid the small departures from whole numbers the
357
+ // scaling would incur.
347
358
348
359
// For e, prec is # digits after the decimal
349
360
// For f, prec is # digits after the decimal
@@ -362,50 +373,36 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
362
373
}
363
374
364
375
int num_digits_left = num_digits ;
365
- if (f >= FPCONST (10.0 )) {
376
+ // If f_int is nonzero, it's because 1.0 < f < 2**32, so the integer
377
+ // part is fully represented in f_int (a uint32_t).
378
+ if (f_int >= 10 ) {
366
379
// Print any leading digits to bring f down to < 10.
367
- // As above, we avoid modifying f to avoid distorting whole numbers.
368
- // Instead, we construct a comparison value that is always a whole
369
- // number (because it does not involve multiplying by any non-whole
370
- // numbers) and subtract that as we print each digit.
380
+ // We work with an integer version of the whole-number part of f,
381
+ // then adjust f only by subtracting integers as we print each
382
+ // digit. This avoids distorting f via multiplication by inexact
383
+ // negative powers of 10.
384
+ // u_int was already set to 10**e when f_int was set up.
371
385
for (int digit_index = e ; digit_index > 0 ; -- digit_index ) {
372
- // Construct the power-of-10 "unit" for this digit by multiplying
373
- // up powers of 10 (so it remains a whole number as long as
374
- // possible). Because we start with the highest-value digit,
375
- // and because dividing by 10 would spoil our guarantee of
376
- // wholeness, we build it up from scratch every digit.
377
- FPTYPE unit = FPCONST (1.0 );
378
- // Re-use the idiom from finding e to make unit = 10^digit_index.
379
- const FPTYPE * pos_pow_2 = g_pos_pow ;
380
- for (int ee = digit_index , e2 = FPDECEXP ; e2 ; e2 >>= 1 , pos_pow_2 ++ ) {
381
- if (ee >= e2 ) {
382
- ee -= e2 ;
383
- unit *= * pos_pow_2 ;
384
- }
385
- }
386
- // Step through the 10 possible values of this digit until we
387
- // find the one before going beyond f.
388
- int d ;
389
- FPTYPE cumulated_units = FPCONST (0.0 );
390
- for (d = 0 ; d < 10 ; ++ d ) {
391
- if (f < cumulated_units + unit ) {
392
- break ;
393
- }
394
- cumulated_units += unit ;
395
- }
386
+ // Integer division will safely give us the leading digit.
387
+ int d = f_int / u_int ;
388
+ f_int -= (d * u_int );
389
+ // Reduce our full floating point value by the integer value we're
390
+ // printing.
391
+ f -= (FPTYPE )(d * u_int );
396
392
* s ++ = '0' + d ;
397
- f -= cumulated_units ;
398
393
if (dec == 0 && prec > 0 ) {
399
394
* s ++ = '.' ;
400
395
}
401
396
-- dec ;
402
397
-- num_digits_left ;
398
+ // Integer division safely reduces the integer unit base.
399
+ u_int /= 10 ;
403
400
// Special case the last digit.
404
401
if (num_digits_left == 0 ) {
405
- // We're going to fall through to the rounding code which expects
402
+ // We're going to fall through to rounding code which expects
406
403
// f to be a residual in the range 1 <= f < 10, and will apply
407
- // rounding if it's >= 5. So now we need to construct that residual.
408
- f *= (FPCONST (10 . ) / unit );
404
+ // rounding if it's >= 5. So we need to construct the residual.
405
+ f *= (FPCONST (1 . ) / u_int );
409
406
break ;
410
407
}
411
408
}
0 commit comments