The methods to multiply a Duration by a float are currently implemented by converting to that float type (as seconds), multiplying, and then converting back to a Duration. This implies unnecessary rounding that loses precision in cases that ideally wouldn't.
It is particularly surprising that multiplying by 1.0 can change a duration, as floating point multiplication by 1.0 does preserve numeric values exactly.
use std::time::Duration;
fn main() {
let d1 = Duration::from_nanos_u128(1 << 90);
let d2 = Duration::from_nanos_u128(2 << 90);
let d3 = Duration::from_nanos_u128(3 << 90);
// Each of these asserts fail
assert_eq!(d1.mul_f32(1.0), d1);
assert_eq!(d1.mul_f32(2.0), d2);
assert_eq!(d1.mul_f32(3.0), d3);
assert_eq!(d2.mul_f32(1.5), d3);
// This panics due to rounding up
Duration::MAX.mul_f32(1.0);
}
I expected these methods to behave just like floating point multiplication: As if the exact result was rounded to the resulting type.
The above uses very long durations, but for more realistic examples, this can be observed with durations like:
100ms
[src/main.rs:5:5] d = 100ms
[src/main.rs:6:5] d.mul_f32(1.0) = 100.000001ms
[src/main.rs:7:5] d.mul_f32(2.0) = 200.000003ms
[src/main.rs:8:5] d.mul_f32(3.0) = 300.000012ms
[src/main.rs:9:5] d * 1 = 100ms
[src/main.rs:10:5] d * 2 = 200ms
[src/main.rs:11:5] d * 3 = 300ms
1s + 111ns
[src/main.rs:5:5] d = 1.000000111s
[src/main.rs:6:5] d.mul_f32(1.0) = 1.000000119s
[src/main.rs:7:5] d.mul_f32(2.0) = 2.000000238s
[src/main.rs:8:5] d.mul_f32(3.0) = 3.000000477s
[src/main.rs:9:5] d * 1 = 1.000000111s
[src/main.rs:10:5] d * 2 = 2.000000222s
[src/main.rs:11:5] d * 3 = 3.000000333s
The methods to multiply a
Durationby a float are currently implemented by converting to that float type (as seconds), multiplying, and then converting back to aDuration. This implies unnecessary rounding that loses precision in cases that ideally wouldn't.It is particularly surprising that multiplying by
1.0can change a duration, as floating point multiplication by1.0does preserve numeric values exactly.I expected these methods to behave just like floating point multiplication: As if the exact result was rounded to the resulting type.
The above uses very long durations, but for more realistic examples, this can be observed with durations like:
100ms
1s + 111ns