about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/core/src/fmt/num.rs11
-rw-r--r--library/core/tests/fmt/num.rs20
2 files changed, 24 insertions, 7 deletions
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index 4f42f73ebba..778515f8616 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -309,7 +309,6 @@ macro_rules! impl_Exp {
                     n /= 10;
                     exponent += 1;
                 }
-
                 let (added_precision, subtracted_precision) = match f.precision() {
                     Some(fmt_prec) => {
                         // number of decimal digits minus 1
@@ -331,9 +330,15 @@ macro_rules! impl_Exp {
                     let rem = n % 10;
                     n /= 10;
                     exponent += 1;
-                    // round up last digit
-                    if rem >= 5 {
+                    // round up last digit, round to even on a tie
+                    if rem > 5 || (rem == 5 && (n % 2 != 0 || subtracted_precision > 1 )) {
                         n += 1;
+                        // if the digit is rounded to the next power
+                        // instead adjust the exponent
+                        if n.ilog10() > (n - 1).ilog10() {
+                            n /= 10;
+                            exponent += 1;
+                        }
                     }
                 }
                 (n, exponent, exponent, added_precision)
diff --git a/library/core/tests/fmt/num.rs b/library/core/tests/fmt/num.rs
index b9ede65c9ff..1ddcd5ab795 100644
--- a/library/core/tests/fmt/num.rs
+++ b/library/core/tests/fmt/num.rs
@@ -128,28 +128,40 @@ fn test_format_int_exp_precision() {
     let big_int: u32 = 314_159_265;
     assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int)));
 
-    //test adding precision
+    // test adding precision
     assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
     assert_eq!(format!("{:.10e}", i16::MIN), "-3.2768000000e4");
     assert_eq!(format!("{:.10e}", i32::MIN), "-2.1474836480e9");
     assert_eq!(format!("{:.20e}", i64::MIN), "-9.22337203685477580800e18");
     assert_eq!(format!("{:.40e}", i128::MIN), "-1.7014118346046923173168730371588410572800e38");
 
-    //test rounding
+    // test rounding
     assert_eq!(format!("{:.1e}", i8::MIN), "-1.3e2");
     assert_eq!(format!("{:.1e}", i16::MIN), "-3.3e4");
     assert_eq!(format!("{:.1e}", i32::MIN), "-2.1e9");
     assert_eq!(format!("{:.1e}", i64::MIN), "-9.2e18");
     assert_eq!(format!("{:.1e}", i128::MIN), "-1.7e38");
 
-    //test huge precision
+    // test huge precision
     assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000)));
     //test zero precision
     assert_eq!(format!("{:.0e}", 1), format!("1e0",));
     assert_eq!(format!("{:.0e}", 35), format!("4e1",));
 
-    //test padding with precision (and sign)
+    // test padding with precision (and sign)
     assert_eq!(format!("{:+10.3e}", 1), "  +1.000e0");
+
+    // test precision remains correct when rounding to next power
+
+    for i in i16::MIN..=i16::MAX {
+        for p in 0..=5 {
+            assert_eq!(
+                format!("{i:.p$e}"),
+                format!("{:.p$e}", f32::from(i)),
+                "integer {i} at precision {p}"
+            );
+        }
+    }
 }
 
 #[test]