Skip to content

Loss of precision in Duration::mul_f32 (and mul_f64) #149794

Open

Description

@quaternic

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

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Dec 8, 2025
  2. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    A-floating-pointArea: Floating point numbers and arithmetic
    A-timeArea: `std::time`
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Dec 9, 2025
  3. added a commit that references this issue on Jan 27, 2026
    5b8b932
  4. tgross35 commented on May 18, 2026

    @tgross35
    Member

    The library team decided against changing these reasonably fast implementations to one that is slower but more accurate, so #155133 updated documentation to illustrate the precision issue.

    I think it could be a good idea to ACP mul_f128/div_f128 and make sure those versions are correctly rounded, then (once stable) mention it in the f32/f64 methods for users who want correct rounding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-floating-pointArea: Floating point numbers and arithmeticA-timeArea: `std::time`C-bugCategory: This is a bug.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions