Skip to content

clarify non-determinism docs for algebraic operations - #160496

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
RalfJung:algebraic-nondet
Aug 5, 2026
Merged

clarify non-determinism docs for algebraic operations#160496
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
RalfJung:algebraic-nondet

Conversation

@RalfJung

@RalfJung RalfJung commented Aug 4, 2026

Copy link
Copy Markdown
Member

This caused some confusion on lobsters so it seems worth clarifying the docs a bit.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Aug 4, 2026
@rustbot

rustbot commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: libs
  • libs expanded to 12 candidates
  • Random selection from 6 candidates

@Darksonn Darksonn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rust-bors

rust-bors Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 15dd0d6 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-bors rust-bors Bot 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-review Status: Awaiting review from the assignee but also interested parties. labels Aug 4, 2026
@rust-bors rust-bors Bot 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 Aug 4, 2026
@rust-bors

rust-bors Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 421a5cc79056cf09ba8dbc52e20e070f4e6f71c3 was pushed.

This pull request was unapproved.

@RalfJung

RalfJung commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

I realized that the guarantee should be assert_eq!(x1.to_bits(), x1.to_bits());, in case a NaN is returned.

@RalfJung

RalfJung commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

@bors r=Darksonn

@rust-bors

rust-bors Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 421a5cc has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-bors rust-bors Bot 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 Aug 4, 2026
@purplesyringa

Copy link
Copy Markdown
Contributor

As the person that got confused, thanks :3 The assert_eq!(x1.to_bits(), x1.to_bits()); line in particular confirms the proper intuition for me.

Comment thread library/core/src/primitive_docs.rs Outdated
/// let x2 = a.algebraic_add(b);
/// assert_eq!(x1.to_bits(), x1.to_bits()); // this is guaranteed
/// # if false {
/// assert_eq!(x1, x2); // but this may fail

@Darksonn Darksonn Aug 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing about the bits here? Even with + it could fail due to nan.

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You think that's more clear? Sure, we can do that.

@rust-bors rust-bors Bot 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 Aug 4, 2026
@rust-bors

rust-bors Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 7b4c6fcc11c5eb07530fd7665e9d7a6499c88764 was pushed.

This pull request was unapproved.

/// assert_eq!(x1.to_bits(), x1.to_bits()); // this is guaranteed
/// # if false {
/// assert_eq!(x1.to_bits(), x2.to_bits()); // but this may fail
/// assert!(!x2.is_nan()); // this may also fail, even if there was no NaN input

@RalfJung RalfJung Aug 4, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also clarified that the NaN here can arise spuriously

View changes since the review

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful to hear in more detail how NaNs can arise spuriously. And maybe move this out of the example and to the top-level? Cause that's a pretty significant impact.

Thanks for adding more detail!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be more specific in why this is good to know, consider the following, with the assumption that the inputs are not NaN:

fn pairwise_sum(values: &[f64]) -> f64 {
    let n = values.len();
    if n > 128 {
        let half = n / 2;
        pairwise_sum(&values[0..half])
            + pairwise_sum(&values[half..n])
    } else {
        let mut total: f64 = 0.0;
        for value in values {
            total = total.algebraic_add(*value);
        }
        total
    }
}

My understanding is that normal float addition will never result in NaN. Can this function result in NaNs, given it's all addition and not clear how it could optimize into any other operation?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess inf + -inf is NaN. But assuming all positive numbers, as in the current example.

@RalfJung RalfJung Aug 4, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs say that no guarantee is made about the return value. That implies no guarantee about absence of NaN.

I don't actually know if anything LLVM does can cause funny NaNs here, but I think if we want to explore providing non-NaN guarantees here then that should be a new issue. Even if LLVM doesn't do this today, I think the LangRef permits them to do it in the future. This PR just clarifies the intent of what we had already written: Unsafe code must not rely on any property of the return value for soundness. In practice, we'd treat it as a bug if the code above produced a NaN as it violates the last sentence ("implementations will generally do their best to pick a reasonable tradeoff between performance and accuracy of the result"), but it would not be a soundness bug.

@Darksonn

Darksonn commented Aug 4, 2026

Copy link
Copy Markdown
Member

@bors r+ rollup

@rust-bors

rust-bors Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 66175a7 has been approved by Darksonn

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 10. This pull request will be tested once the tree is reopened.

Reason for tree closure: manually handling queue due to backlog

@rust-bors rust-bors Bot added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Aug 4, 2026
@rust-bors rust-bors Bot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Aug 4, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 4, 2026
clarify non-determinism docs for algebraic operations

This caused some confusion [on lobsters](https://lobste.rs/s/jnznnu/faster_floating_point_math_with_rust_s_new) so it seems worth clarifying the docs a bit.
rust-bors Bot pushed a commit that referenced this pull request Aug 5, 2026
…uwer

Rollup of 22 pull requests

Successful merges:

 - #160426 (`rust-analyzer` subtree update)
 - #160372 (Derive the allocator used by tools from rustc's allocator)
 - #146882 (fully deprecate the legacy integral modules)
 - #158727 (std: use `readdir` on nearly all UNIX platforms)
 - #159727 (Various steps in moving away from the big reflection enum to reflection functions)
 - #160443 (normalize in relations, not generalize, when relating infer with alias)
 - #160457 (implement -Zllvm-target-feature)
 - #160480 (Single-pass ASCII lower/upper case conversion)
 - #160502 (Reduce number of miri tests executed on PR CI)
 - #157430 (std::random: use little-endian for reproducibility)
 - #158110 (fix macro attribute feature-gate span)
 - #159975 (Use real ThinVec in StmtDebugInfos)
 - #160001 (Suggest mutable method when iterating over binding)
 - #160024 (Fix mono reachability with no-op landing pads)
 - #160154 (Add regression test for HRTB associated type projection closure)
 - #160176 (No more `tests/ui/issues`!)
 - #160326 (Remove hidden_glob_reexports)
 - #160407 (Add regression tests for a number of ICEs and diagnostics issues labelled `E-needs-test`)
 - #160430 (bootstrap: Don't produce mutated/filtered PathSets during command-line matching)
 - #160472 (Minor fixes to `core::io` & `alloc::io` Documentation)
 - #160486 (Remove unused `FreeRegionsVisitor`)
 - #160496 (clarify non-determinism docs for algebraic operations)

Failed merges:

 - #160501 (Add bootstrap CLI snapshot test for testing miri)
@rust-bors
rust-bors Bot merged commit 85cfb50 into rust-lang:main Aug 5, 2026
13 checks passed
@rustbot rustbot added this to the 1.99.0 milestone Aug 5, 2026
rust-timer added a commit that referenced this pull request Aug 5, 2026
Rollup merge of #160496 - RalfJung:algebraic-nondet, r=Darksonn

clarify non-determinism docs for algebraic operations

This caused some confusion [on lobsters](https://lobste.rs/s/jnznnu/faster_floating_point_math_with_rust_s_new) so it seems worth clarifying the docs a bit.
@RalfJung
RalfJung deleted the algebraic-nondet branch August 5, 2026 06:28
RalfJung pushed a commit to rust-lang/miri that referenced this pull request Aug 5, 2026
…uwer

Rollup of 22 pull requests

Successful merges:

 - rust-lang/rust#160426 (`rust-analyzer` subtree update)
 - rust-lang/rust#160372 (Derive the allocator used by tools from rustc's allocator)
 - rust-lang/rust#146882 (fully deprecate the legacy integral modules)
 - rust-lang/rust#158727 (std: use `readdir` on nearly all UNIX platforms)
 - rust-lang/rust#159727 (Various steps in moving away from the big reflection enum to reflection functions)
 - rust-lang/rust#160443 (normalize in relations, not generalize, when relating infer with alias)
 - rust-lang/rust#160457 (implement -Zllvm-target-feature)
 - rust-lang/rust#160480 (Single-pass ASCII lower/upper case conversion)
 - rust-lang/rust#160502 (Reduce number of miri tests executed on PR CI)
 - rust-lang/rust#157430 (std::random: use little-endian for reproducibility)
 - rust-lang/rust#158110 (fix macro attribute feature-gate span)
 - rust-lang/rust#159975 (Use real ThinVec in StmtDebugInfos)
 - rust-lang/rust#160001 (Suggest mutable method when iterating over binding)
 - rust-lang/rust#160024 (Fix mono reachability with no-op landing pads)
 - rust-lang/rust#160154 (Add regression test for HRTB associated type projection closure)
 - rust-lang/rust#160176 (No more `tests/ui/issues`!)
 - rust-lang/rust#160326 (Remove hidden_glob_reexports)
 - rust-lang/rust#160407 (Add regression tests for a number of ICEs and diagnostics issues labelled `E-needs-test`)
 - rust-lang/rust#160430 (bootstrap: Don't produce mutated/filtered PathSets during command-line matching)
 - rust-lang/rust#160472 (Minor fixes to `core::io` & `alloc::io` Documentation)
 - rust-lang/rust#160486 (Remove unused `FreeRegionsVisitor`)
 - rust-lang/rust#160496 (clarify non-determinism docs for algebraic operations)

Failed merges:

 - rust-lang/rust#160501 (Add bootstrap CLI snapshot test for testing miri)
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.

5 participants