Merged Duration Debug tie rounding with existing rounding logic

This commit is contained in:
Josh Kaplan 2025-12-22 09:20:56 -05:00
parent 95302b2537
commit c74aa910ca
No known key found for this signature in database
GPG key ID: 1D24245906A07E64

View file

@ -1315,9 +1315,12 @@ impl fmt::Debug for Duration {
// 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. When the first digit is exactly 5, rounding
// follows IEEE-754 round-ties-to-even semantics.
let integer_part = if fractional_part > 0 && fractional_part == divisor * 5 {
// remaining ones is >= 5. When the first digit is exactly 5, rounding
// follows IEEE-754 round-ties-to-even semantics: we only round up
// if the last written digit is odd.
let integer_part = if fractional_part > 0 && fractional_part >= divisor * 5 {
// For ties (fractional_part == divisor * 5), only round up if last digit is odd
let is_tie = fractional_part == divisor * 5;
let last_digit_is_odd = if pos > 0 {
(buf[pos - 1] - b'0') % 2 == 1
} else {
@ -1325,12 +1328,20 @@ impl fmt::Debug for Duration {
(integer_part % 2) == 1
};
if last_digit_is_odd {
if is_tie && !last_digit_is_odd {
Some(integer_part)
} else {
// 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;
@ -1339,43 +1350,20 @@ impl fmt::Debug for Duration {
}
}
if carry { integer_part.checked_add(1) } else { Some(integer_part) }
} else {
Some(integer_part)
}
} else 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;
// 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 {
// If `integer_part == u64::MAX` and precision < 9, any
// carry of the overflow during rounding of the
// `fractional_part` into the `integer_part` will cause the
// `integer_part` itself to overflow. Avoid this by using an
// `Option<u64>`, with `None` representing `u64::MAX + 1`.
integer_part.checked_add(1)
} else {
buf[rev_pos] = b'0';
Some(integer_part)
}
}
// 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 {
// If `integer_part == u64::MAX` and precision < 9, any
// carry of the overflow during rounding of the
// `fractional_part` into the `integer_part` will cause the
// `integer_part` itself to overflow. Avoid this by using an
// `Option<u64>`, with `None` representing `u64::MAX + 1`.
integer_part.checked_add(1)
} else {
Some(integer_part)
}
} else {
Some(integer_part)
};