Skip to content

Commit b917524

Browse files
committed
Auto merge of rust-lang#116301 - mj10021:issue-115737-fix, r=cuviper
fix rounding issue with exponents in fmt fixes issue rust-lang#115737 , where the decimal places are rounded incorrectly when formatting scientific notation
2 parents ba7c7a3 + 3f0908f commit b917524

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

library/core/src/fmt/num.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,6 @@ macro_rules! impl_Exp {
309309
n /= 10;
310310
exponent += 1;
311311
}
312-
313312
let (added_precision, subtracted_precision) = match f.precision() {
314313
Some(fmt_prec) => {
315314
// number of decimal digits minus 1
@@ -331,9 +330,15 @@ macro_rules! impl_Exp {
331330
let rem = n % 10;
332331
n /= 10;
333332
exponent += 1;
334-
// round up last digit
335-
if rem >= 5 {
333+
// round up last digit, round to even on a tie
334+
if rem > 5 || (rem == 5 && (n % 2 != 0 || subtracted_precision > 1 )) {
336335
n += 1;
336+
// if the digit is rounded to the next power
337+
// instead adjust the exponent
338+
if n.ilog10() > (n - 1).ilog10() {
339+
n /= 10;
340+
exponent += 1;
341+
}
337342
}
338343
}
339344
(n, exponent, exponent, added_precision)

library/core/tests/fmt/num.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -128,28 +128,40 @@ fn test_format_int_exp_precision() {
128128
let big_int: u32 = 314_159_265;
129129
assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int)));
130130

131-
//test adding precision
131+
// test adding precision
132132
assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
133133
assert_eq!(format!("{:.10e}", i16::MIN), "-3.2768000000e4");
134134
assert_eq!(format!("{:.10e}", i32::MIN), "-2.1474836480e9");
135135
assert_eq!(format!("{:.20e}", i64::MIN), "-9.22337203685477580800e18");
136136
assert_eq!(format!("{:.40e}", i128::MIN), "-1.7014118346046923173168730371588410572800e38");
137137

138-
//test rounding
138+
// test rounding
139139
assert_eq!(format!("{:.1e}", i8::MIN), "-1.3e2");
140140
assert_eq!(format!("{:.1e}", i16::MIN), "-3.3e4");
141141
assert_eq!(format!("{:.1e}", i32::MIN), "-2.1e9");
142142
assert_eq!(format!("{:.1e}", i64::MIN), "-9.2e18");
143143
assert_eq!(format!("{:.1e}", i128::MIN), "-1.7e38");
144144

145-
//test huge precision
145+
// test huge precision
146146
assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000)));
147147
//test zero precision
148148
assert_eq!(format!("{:.0e}", 1), format!("1e0",));
149149
assert_eq!(format!("{:.0e}", 35), format!("4e1",));
150150

151-
//test padding with precision (and sign)
151+
// test padding with precision (and sign)
152152
assert_eq!(format!("{:+10.3e}", 1), " +1.000e0");
153+
154+
// test precision remains correct when rounding to next power
155+
156+
for i in i16::MIN..=i16::MAX {
157+
for p in 0..=5 {
158+
assert_eq!(
159+
format!("{i:.p$e}"),
160+
format!("{:.p$e}", f32::from(i)),
161+
"integer {i} at precision {p}"
162+
);
163+
}
164+
}
153165
}
154166

155167
#[test]

0 commit comments

Comments
 (0)