Implement rounding for Durations 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.
This commit is contained in:
Lukas Kalbertodt 2018-05-16 14:46:37 +02:00
parent 9eeb13fdd1
commit 2a28ac31e9
No known key found for this signature in database
GPG key ID: 3CBAF4153F818627
2 changed files with 51 additions and 7 deletions

View file

@ -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");
}

View file

@ -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);