about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Kalbertodt <lukas.kalbertodt@gmail.com>2018-05-16 14:46:37 +0200
committerLukas Kalbertodt <lukas.kalbertodt@gmail.com>2018-05-16 14:46:37 +0200
commit2a28ac31e9abe0a01861bfffed85872431cc6b72 (patch)
treed652d7cf0dc36ccaf103b99b14b5c908097d3684
parent9eeb13fdd1c10de7f489e7fc910686c6d492398e (diff)
downloadrust-2a28ac31e9abe0a01861bfffed85872431cc6b72.tar.gz
rust-2a28ac31e9abe0a01861bfffed85872431cc6b72.zip
Implement rounding for `Duration`s Debug output
Rounding is done like for printing floating point numbers. If the
first digit which isn't printed (due to the precision parameter) is
larger than '4', the number is rounded up.
-rw-r--r--src/libcore/tests/time.rs22
-rw-r--r--src/libcore/time.rs36
2 files changed, 51 insertions, 7 deletions
diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs
index bfb5369cf8f..b0abdc749f6 100644
--- a/src/libcore/tests/time.rs
+++ b/src/libcore/tests/time.rs
@@ -202,13 +202,19 @@ fn debug_formatting_precision_zero() {
     assert_eq!(format!("{:.0?}", Duration::new(0, 123)), "123ns");
 
     assert_eq!(format!("{:.0?}", Duration::new(0, 1_001)), "1µs");
-    assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "1µs");
+    assert_eq!(format!("{:.0?}", Duration::new(0, 1_499)), "1µs");
+    assert_eq!(format!("{:.0?}", Duration::new(0, 1_500)), "2µs");
+    assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "2µs");
 
     assert_eq!(format!("{:.0?}", Duration::new(0, 1_000_001)), "1ms");
-    assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "1ms");
+    assert_eq!(format!("{:.0?}", Duration::new(0, 1_499_999)), "1ms");
+    assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms");
+    assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "2ms");
 
     assert_eq!(format!("{:.0?}", Duration::new(1, 000_000_001)), "1s");
-    assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "1s");
+    assert_eq!(format!("{:.0?}", Duration::new(1, 499_999_999)), "1s");
+    assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s");
+    assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "2s");
 }
 
 #[test]
@@ -222,15 +228,19 @@ fn debug_formatting_precision_two() {
     assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs");
     assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs");
     assert_eq!(format!("{:.2?}", Duration::new(0, 7_100)), "7.10µs");
-    assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "1.99µs");
+    assert_eq!(format!("{:.2?}", Duration::new(0, 7_109)), "7.11µs");
+    assert_eq!(format!("{:.2?}", Duration::new(0, 7_199)), "7.20µs");
+    assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "2.00µs");
 
     assert_eq!(format!("{:.2?}", Duration::new(0, 1_000_000)), "1.00ms");
     assert_eq!(format!("{:.2?}", Duration::new(0, 3_001_000)), "3.00ms");
     assert_eq!(format!("{:.2?}", Duration::new(0, 3_100_000)), "3.10ms");
-    assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "1.99ms");
+    assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "2.00ms");
 
     assert_eq!(format!("{:.2?}", Duration::new(1, 000_000_000)), "1.00s");
     assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s");
     assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s");
-    assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "8.99s");
+    assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s");
+    assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s");
+    assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s");
 }
diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index a0a48e8493c..34bf3637f29 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -498,7 +498,7 @@ impl fmt::Debug for Duration {
         /// to be less than `10 * divisor`!
         fn fmt_decimal(
             f: &mut fmt::Formatter,
-            integer_part: u64,
+            mut integer_part: u64,
             mut fractional_part: u32,
             mut divisor: u32,
         ) -> fmt::Result {
@@ -522,6 +522,40 @@ impl fmt::Debug for Duration {
                 pos += 1;
             }
 
+            // If a precision < 9 was specified, there may be some non-zero
+            // digits left that weren't written into the buffer. In that case we
+            // need to perform rounding to match the semantics of printing
+            // normal floating point numbers. However, we only need to do work
+            // when rounding up. This happens if the first digit of the
+            // remaining ones is >= 5.
+            if fractional_part > 0 && fractional_part >= divisor * 5 {
+                // Round up the number contained in the buffer. We go through
+                // the buffer backwards and keep track of the carry.
+                let mut rev_pos = pos;
+                let mut carry = true;
+                while carry && rev_pos > 0 {
+                    rev_pos -= 1;
+
+                    // If the digit in the buffer is not '9', we just need to
+                    // increment it and can stop then (since we don't have a
+                    // carry anymore). Otherwise, we set it to '0' (overflow)
+                    // and continue.
+                    if buf[rev_pos] < b'9' {
+                        buf[rev_pos] += 1;
+                        carry = false;
+                    } else {
+                        buf[rev_pos] = b'0';
+                    }
+                }
+
+                // If we still have the carry bit set, that means that we set
+                // the whole buffer to '0's and need to increment the integer
+                // part.
+                if carry {
+                    integer_part += 1;
+                }
+            }
+
             // If we haven't emitted a single fractional digit and the precision
             // wasn't set to a non-zero value, we don't print the decimal point.
             let end = f.precision().unwrap_or(pos);