@@ -378,16 +378,30 @@ fn format_float_decimal(
378378/// - The returned `String` contains the digits `XXX`, _without_ the separating
379379/// `.` (the caller must add that to get a valid scientific format number).
380380/// - `e` is an integer exponent.
381- fn bd_to_string_exp_with_prec ( bd : & BigDecimal , precision : u64 ) -> ( String , i64 ) {
381+ fn bd_to_string_exp_with_prec ( bd : & BigDecimal , precision : usize ) -> ( String , i64 ) {
382+ // TODO: A lot of time is spent in `with_prec` computing the exact number
383+ // of digits, it might be possible to save computation time by doing a rough
384+ // division followed by arithmetics on `digits` to round if necessary (using
385+ // `fast_inc`).
386+
382387 // Round bd to precision digits (including the leading digit)
383- // We call `with_prec` twice as it will produce an extra digit if rounding overflows
384- // (e.g. 9995.with_prec(3) => 1000 * 10^1, but we want 100 * 10^2).
385- let bd_round = bd. with_prec ( precision) . with_prec ( precision) ;
388+ // Note that `with_prec` will produce an extra digit if rounding overflows
389+ // (e.g. 9995.with_prec(3) => 1000 * 10^1, but we want 100 * 10^2), we compensate
390+ // for that later.
391+ let bd_round = bd. with_prec ( precision as u64 ) ;
386392
387393 // Convert to the form XXX * 10^-p (XXX is precision digit long)
388- let ( frac, p) = bd_round. as_bigint_and_exponent ( ) ;
394+ let ( frac, mut p) = bd_round. as_bigint_and_exponent ( ) ;
395+
396+ let mut digits = frac. to_str_radix ( 10 ) ;
397+
398+ // In the unlikely case we had an overflow, correct for that.
399+ if digits. len ( ) == precision + 1 {
400+ debug_assert ! ( & digits[ precision..] == "0" ) ;
401+ digits. truncate ( precision) ;
402+ p -= 1 ;
403+ }
389404
390- let digits = frac. to_str_radix ( 10 ) ;
391405 // If we end up with scientific formatting, we would convert XXX to X.XX:
392406 // that divides by 10^(precision-1), so add that to the exponent.
393407 let exponent = -p + precision as i64 - 1 ;
@@ -416,7 +430,7 @@ fn format_float_scientific(
416430 } ;
417431 }
418432
419- let ( digits, exponent) = bd_to_string_exp_with_prec ( bd, precision as u64 + 1 ) ;
433+ let ( digits, exponent) = bd_to_string_exp_with_prec ( bd, precision + 1 ) ;
420434 let ( first_digit, remaining_digits) = digits. split_at ( 1 ) ;
421435
422436 let dot =
@@ -454,7 +468,7 @@ fn format_float_shortest(
454468 } ;
455469 }
456470
457- let ( digits, exponent) = bd_to_string_exp_with_prec ( bd, precision as u64 ) ;
471+ let ( digits, exponent) = bd_to_string_exp_with_prec ( bd, precision) ;
458472
459473 if exponent < -4 || exponent >= precision as i64 {
460474 // Scientific-ish notation (with a few differences)
0 commit comments