Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use rounding in float to Duration conversion methods #96051

Merged
merged 6 commits into from
May 27, 2022

Conversation

newpavlov
Copy link
Contributor

Closes #96045

@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Apr 14, 2022
@rust-highfive
Copy link
Collaborator

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with r? rust-lang/libs-api @rustbot label +T-libs-api to request review from a libs-api team reviewer. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • a stabilization of a library feature
  • introducing new or changes existing unstable library APIs
  • changes to public documentation in ways that create new stability guarantees

@rust-highfive
Copy link
Collaborator

r? @kennytm

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 14, 2022
@newpavlov
Copy link
Contributor Author

r? @nagisa

library/core/src/time.rs Show resolved Hide resolved
library/core/src/time.rs Outdated Show resolved Hide resolved
@Stargateur
Copy link
Contributor

there is really no tool for rounding float ? we are force to do it at hand in Duration ?

@nagisa
Copy link
Member

nagisa commented Apr 15, 2022

there is really no tool for rounding float ? we are force to do it at hand in Duration ?

Truncating and/or correctly rounded conversions to/from some formats such as 32-bit or 64-bit integers are provided, usually by hardware nowadays. Duration, however, is special in that it is a 96-bit integer with a specific format (the 32-bit nanosecond counter is expected to be in a half-open range 0..1E9) so implementing it ourselves is most likely the only reasonable approach.

@newpavlov
Copy link
Contributor Author

Well, another theoretical alternative is to migrate Duration from the somewhat weird 96-bit type which does not use the 32-bit half fully and to use simple 128-bit nanosecond counter. It would require additional conversions when we talk to most OSes, but it would significantly simplify other parts.

@Stargateur
Copy link
Contributor

Stargateur commented Apr 15, 2022

@newpavlov to be clear I never say we should do this, I just wondering if there was a tool to manipulate float to avoid doing such complex operation in the code of Duration. (I find none)

@nagisa nagisa added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). I-libs-nominated Nominated for discussion during a libs team meeting. I-libs-api-nominated Nominated for discussion during a libs-api team meeting. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 24, 2022
@nagisa
Copy link
Member

nagisa commented Apr 24, 2022

Nominating for a T-libs decision on:

a) Do we want rounding after all?
b) What kind of tie resolution should be used if a.

@joshtriplett
Copy link
Member

@nagisa

Reviewed in the @rust-lang/libs meeting.

a) Yes, we want rounding.
b) Round-to-even would be preferable, assuming it isn't massively less performance to implement (e.g. the difference between hardware-assisted and not).

@nagisa nagisa added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). I-libs-nominated Nominated for discussion during a libs team meeting. I-libs-api-nominated Nominated for discussion during a libs-api team meeting. labels May 1, 2022
@nagisa
Copy link
Member

nagisa commented May 1, 2022

I don't believe there are any significant performance concerns here since we aren't able to use any hardware acceleration for the conversion either way, and I would be surprised if any ever showed up. The only concern with different tie resolution models I believe is just that one of them is just significantly more nasty to implement and understand.

@newpavlov
Copy link
Contributor Author

@bors r+

@bors
Copy link
Contributor

bors commented May 27, 2022

📌 Commit 06af3a6 has been approved by newpavlov

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 27, 2022
@newpavlov
Copy link
Contributor Author

@bors r-

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels May 27, 2022
@inquisitivecrystal
Copy link
Contributor

@newpavlov: when approving, remember to do r=nagisa,joshtriplett instead of r+.

@newpavlov
Copy link
Contributor Author

@bors r=nagisa,joshtriplett

@bors
Copy link
Contributor

bors commented May 27, 2022

📌 Commit 6495963 has been approved by nagisa,joshtriplett

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 27, 2022
bors added a commit to rust-lang-ci/rust that referenced this pull request May 27, 2022
…piler-errors

Rollup of 3 pull requests

Successful merges:

 - rust-lang#96051 (Use rounding in float to Duration conversion methods)
 - rust-lang#97066 (rustdoc: Remove `ItemFragment(Kind)`)
 - rust-lang#97436 (Update `triagebot.toml` for macos ping group)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit e3813e4 into rust-lang:master May 27, 2022
@bors
Copy link
Contributor

bors commented May 27, 2022

⌛ Testing commit 6495963 with merge 9a42c65...

@rustbot rustbot added this to the 1.63.0 milestone May 27, 2022
@newpavlov newpavlov deleted the duration_rounding branch May 27, 2022 08:34
github-actions bot pushed a commit to gnoliyil/fuchsia that referenced this pull request Jun 14, 2022
Re-enable tests that were disabled due to floating-point arithmetic
changes in the rust standard library. The behavior of floating-point
arithmetic went back to rounding vs truncating in
rust-lang/rust#96051, so it's safe to enable
these tests again.

A new bug has been filed to track the work to avoid doing
floating-point arithmetic. The complication is that `StepRng` is
behaving in unexpected ways and preventing migration of the existing
unit tests.

Fixed: 92923
Bug: 102199

Change-Id: I3372193a8d59f1bc0d816e9921056bb85fb290d4
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/643581
Reviewed-by: Jake Fried <friedj@google.com>
Reviewed-by: Ghanan Gowripalan <ghanan@google.com>
Commit-Queue: Tony Gong <gongt@google.com>
tkmcmaster added a commit to FamilySearch/pewpew that referenced this pull request Sep 7, 2022
- Rust version 1.63 changed how they convert float to Durations. Previously they truncated, now they round
  - https://github.com/rust-lang/rust/releases/tag/1.63.0
  - rust-lang/rust#96051
  - 'Rounding is now used when converting a float to a Duration. The converted duration can differ slightly from what it was.'
tkmcmaster added a commit to FamilySearch/pewpew that referenced this pull request Sep 7, 2022
* Updated dependencies Cargo and npm

* Fixed clippy and format warnings

* Fixed tests that are failing in Rust 1.63

- Rust version 1.63 changed how they convert float to Durations. Previously they truncated, now they round
  - https://github.com/rust-lang/rust/releases/tag/1.63.0
  - rust-lang/rust#96051
  - 'Rounding is now used when converting a float to a Duration. The converted duration can differ slightly from what it was.'

* Fixed the names of some variables to match what they are
JohnTitor pushed a commit to JohnTitor/rust that referenced this pull request Oct 24, 2022
…on-try-from-secs-float, r=dtolnay

Stabilize `duration_checked_float`

## Stabilization Report

This stabilization report is for a stabilization of `duration_checked_float`, tracking issue: rust-lang#83400.

### Implementation History

- rust-lang#82179
- rust-lang#90247
- rust-lang#96051
- Changed error type to `FromFloatSecsError` in rust-lang#90247
- rust-lang#96051 changes the rounding mode to round-to-nearest instead of truncate.

## API Summary

This stabilization report proposes the following API to be stabilized in `core`, along with their re-exports in `std`:

```rust
// core::time

impl Duration {
    pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError>;
    pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError>;
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TryFromFloatSecsError { ... }

impl core::fmt::Display for TryFromFloatSecsError { ... }
impl core::error::Error for TryFromFloatSecsError { ... }
```

These functions are made const unstable under `duration_consts_float`, tracking issue rust-lang#72440.

There is an open question in the tracking issue around what the error type should be called which I was hoping to resolve in the context of an FCP.

In this stabilization PR, I have altered the name of the error type to `TryFromFloatSecsError`. In my opinion, the error type shares the name of the method (adjusted to accommodate both types of floats), which is consistent with other error types in `core`, `alloc` and `std` like `TryReserveError` and `TryFromIntError`.

## Experience Report

Code such as this is ready to be converted to a checked API to ensure it is panic free:

```rust
impl Time {
    pub fn checked_add_f64(&self, seconds: f64) -> Result<Self, TimeError> {
        // Fail safely during `f64` conversion to duration
        if seconds.is_nan() || seconds.is_infinite() {
            return Err(TzOutOfRangeError::new().into());
        }

        if seconds.is_sign_positive() {
            self.checked_add(Duration::from_secs_f64(seconds))
        } else {
            self.checked_sub(Duration::from_secs_f64(-seconds))
        }
    }
}
```

See: artichoke/artichoke#2194.

`@rustbot` label +T-libs-api -T-libs

cc `@mbartlett21`
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Oct 24, 2022
…on-try-from-secs-float, r=dtolnay

Stabilize `duration_checked_float`

## Stabilization Report

This stabilization report is for a stabilization of `duration_checked_float`, tracking issue: rust-lang#83400.

### Implementation History

- rust-lang#82179
- rust-lang#90247
- rust-lang#96051
- Changed error type to `FromFloatSecsError` in rust-lang#90247
- rust-lang#96051 changes the rounding mode to round-to-nearest instead of truncate.

## API Summary

This stabilization report proposes the following API to be stabilized in `core`, along with their re-exports in `std`:

```rust
// core::time

impl Duration {
    pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError>;
    pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError>;
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TryFromFloatSecsError { ... }

impl core::fmt::Display for TryFromFloatSecsError { ... }
impl core::error::Error for TryFromFloatSecsError { ... }
```

These functions are made const unstable under `duration_consts_float`, tracking issue rust-lang#72440.

There is an open question in the tracking issue around what the error type should be called which I was hoping to resolve in the context of an FCP.

In this stabilization PR, I have altered the name of the error type to `TryFromFloatSecsError`. In my opinion, the error type shares the name of the method (adjusted to accommodate both types of floats), which is consistent with other error types in `core`, `alloc` and `std` like `TryReserveError` and `TryFromIntError`.

## Experience Report

Code such as this is ready to be converted to a checked API to ensure it is panic free:

```rust
impl Time {
    pub fn checked_add_f64(&self, seconds: f64) -> Result<Self, TimeError> {
        // Fail safely during `f64` conversion to duration
        if seconds.is_nan() || seconds.is_infinite() {
            return Err(TzOutOfRangeError::new().into());
        }

        if seconds.is_sign_positive() {
            self.checked_add(Duration::from_secs_f64(seconds))
        } else {
            self.checked_sub(Duration::from_secs_f64(-seconds))
        }
    }
}
```

See: artichoke/artichoke#2194.

``@rustbot`` label +T-libs-api -T-libs

cc ``@mbartlett21``
jnqnfe added a commit to jnqnfe/pulse-binding-rust that referenced this pull request Jan 9, 2023
version 1.60 of the rust stdlib included a change to improve the accuracy
of calculations in `Duration::try_from_secs_f32/64` (see [1]), which had a
minor breaking change of slightly altering the calculated results. version
1.63 further tweaked this (see [2]).

this commit updates tests to match the new calculated values from 1.63+,
and thus fixes failure running tests in newer stable rust releases and
helps us to fix CI failure. this is done at the expense of breaking the
ability to run the tests with older rust versions, which seems reasonably
acceptable at this time. for the record, the new values used here are
those calculated using version 1.66.

it has been suggested that rather than compare float values directly, it
may be better for this crate to compare via the `float_eq` crate instead.
this would essentially mean switching to a less accurate comparison. since
some time has passed now since i originally encountered this problem, i
think that just updating the values compared against is the best move at
this time, though i am not necessarily against moving to use of `float_eq`
at some point in future if this causes significant problems for users of
older rust versions, or if we encounter further such issues from rust
stdlib changes.

note that in the original issue (see [3]) there were four functions whose
doc-tests were failing, yet only three have needed to be modified here.
the lack of needing to fix the fourth function's tests is presumably as a
result of the changes made in rust v1.63. (the original issue was noticed
with a v1.60 nightly).

[1]: rust-lang/rust#90247
[2]: rust-lang/rust#96051
[3]: #48
thomcc pushed a commit to tcdi/postgrestd that referenced this pull request Feb 10, 2023
…om-secs-float, r=dtolnay

Stabilize `duration_checked_float`

## Stabilization Report

This stabilization report is for a stabilization of `duration_checked_float`, tracking issue: rust-lang/rust#83400.

### Implementation History

- rust-lang/rust#82179
- rust-lang/rust#90247
- rust-lang/rust#96051
- Changed error type to `FromFloatSecsError` in rust-lang/rust#90247
- rust-lang/rust#96051 changes the rounding mode to round-to-nearest instead of truncate.

## API Summary

This stabilization report proposes the following API to be stabilized in `core`, along with their re-exports in `std`:

```rust
// core::time

impl Duration {
    pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError>;
    pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError>;
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TryFromFloatSecsError { ... }

impl core::fmt::Display for TryFromFloatSecsError { ... }
impl core::error::Error for TryFromFloatSecsError { ... }
```

These functions are made const unstable under `duration_consts_float`, tracking issue #72440.

There is an open question in the tracking issue around what the error type should be called which I was hoping to resolve in the context of an FCP.

In this stabilization PR, I have altered the name of the error type to `TryFromFloatSecsError`. In my opinion, the error type shares the name of the method (adjusted to accommodate both types of floats), which is consistent with other error types in `core`, `alloc` and `std` like `TryReserveError` and `TryFromIntError`.

## Experience Report

Code such as this is ready to be converted to a checked API to ensure it is panic free:

```rust
impl Time {
    pub fn checked_add_f64(&self, seconds: f64) -> Result<Self, TimeError> {
        // Fail safely during `f64` conversion to duration
        if seconds.is_nan() || seconds.is_infinite() {
            return Err(TzOutOfRangeError::new().into());
        }

        if seconds.is_sign_positive() {
            self.checked_add(Duration::from_secs_f64(seconds))
        } else {
            self.checked_sub(Duration::from_secs_f64(-seconds))
        }
    }
}
```

See: artichoke/artichoke#2194.

`@rustbot` label +T-libs-api -T-libs

cc `@mbartlett21`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Regression in rounding of Duration::from_secs_f64 in 1.60.0
9 participants