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

copysign with sign being a NaN can have non-portable results #129683

Merged
merged 1 commit into from
Aug 29, 2024

Conversation

RalfJung
Copy link
Member

@RalfJung RalfJung commented Aug 28, 2024

Follow-up to #129559.
Cc @tgross35 @beetrees

There's no portable variant we can recommend instead here, is there? Something with a semantics like "if sign is a NaN, then return self unaltered, otherwise return self with the sign changed to that of sign"?

@rustbot
Copy link
Collaborator

rustbot commented Aug 28, 2024

r? @workingjubilee

rustbot has assigned @workingjubilee.
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

@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 28, 2024
@RalfJung
Copy link
Member Author

r? @thomcc
since you hopefully still have context from #129559

@rustbot rustbot assigned thomcc and unassigned workingjubilee Aug 28, 2024
@bjorn3
Copy link
Member

bjorn3 commented Aug 28, 2024

Doesn't copysign operate on bit level rather than as an arithmetic operation? On riscv copysign would be implemented using fsgnj which is documented as working with individual bits and not canonicalizing NaN. On x86 LLVM uses two andps and an orps which works with individual bits too. On arm64 LLVM uses bif, which too works on individual bits. For C++ https://en.cppreference.com/w/cpp/numeric/math/copysign documents copysign as the only portable way of manipulating the sign of NaN.

@RalfJung
Copy link
Member Author

RalfJung commented Aug 28, 2024

Yes, it does work on the bit level. That is already documented:

If self is a NaN, then a NaN with the same payload as self and the sign bit of sign is returned.

@RalfJung RalfJung changed the title copysign with sign being a NaN is non-portable copysign with sign being a NaN can have non-portable results Aug 28, 2024
@RalfJung
Copy link
Member Author

The point isn't that copysign itself behaves different on different targets, the point is that it can make the sign of a NaN visible and that can be different between different targets. If a floating-point program never uses is_sign_*, copysign, or the conversion to raw bytes, it will behave exactly the same on all platforms -- that's what makes those operations special and why they have some warnings and links in their docs.

@workingjubilee
Copy link
Member

The NaN bit pattern docs don't mention what operations are arithmetic operations.

@thomcc
Copy link
Member

thomcc commented Aug 28, 2024

LGTM
@bors r+ rollup

@bors
Copy link
Contributor

bors commented Aug 28, 2024

📌 Commit 0589dc7 has been approved by thomcc

It is now in the queue for this repository.

@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-review Status: Awaiting review from the assignee but also interested parties. labels Aug 28, 2024
@workingjubilee
Copy link
Member

The following should be consistent, right, even if it isn't specified what the values are?

let nan = f32::NAN;
let sign_a = 1.0_f32.copysign(nan);
let sign_b = 1.0_f32.copysign(f32::from_bits(nan.to_bits()));
assert_eq!(sign_a, sign_b);

@RalfJung
Copy link
Member Author

@workingjubilee yes, from_bits(f.to_bits()) is a perfect round-trip.

@workingjubilee
Copy link
Member

Then we should document that some operations are non-arithmetic operations and what they are.

@RalfJung
Copy link
Member Author

The NaN bit pattern docs don't mention what operations are arithmetic operations.

The NaN rules apply to all float operations except the "bitwise" ones, unless the operation documents something different. The docs do say which ones are "bitwise".

So the use of "arithmetic" in these docs here isn't very meaningful I think -- but I didn't introduce that term into the docs so I am not sure what the original author intended that term to mean.

@workingjubilee
Copy link
Member

I suspect they meant the set that doesn't include abs, copysign, signum, *_bits, and is_sign_*.

@workingjubilee
Copy link
Member

That's what IEEE754 would say, anyways.

I bring this up because that's the precise set we're declaring as having inconstant results, essentially.

@RalfJung
Copy link
Member Author

RalfJung commented Aug 28, 2024

That comment applies more to #129559 than to this PR. I opened #129699 to not lose track.

@workingjubilee
Copy link
Member

Sure!

I am mostly making sure that there's no objection to clarifying this matter further, because I know that even if we "get it", I don't think it will be understood implicitly by everyone.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Aug 28, 2024
copysign with sign being a NaN can have non-portable results

Follow-up to rust-lang#129559.
Cc `@tgross35` `@beetrees`

There's no portable variant we can recommend instead here, is there? Something with a semantics like "if `sign` is a NaN, then return `self` unaltered, otherwise return `self` with the sign changed to that of `sign`"?
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 28, 2024
…iaskrgr

Rollup of 11 pull requests

Successful merges:

 - rust-lang#128166 (Improved `checked_isqrt` and `isqrt` methods)
 - rust-lang#129170 (Add an ability to convert between `Span` and `visit::Location`)
 - rust-lang#129366 (linker: Synchronize native library search in rustc and linker)
 - rust-lang#129467 (derive(SmartPointer): assume pointee from the single generic and better error messages)
 - rust-lang#129494 (format code in tests/ui/threads-sendsync)
 - rust-lang#129527 (Don't use `TyKind` in a lint)
 - rust-lang#129617 (Update books)
 - rust-lang#129673 (Add fmt::Debug to sync::Weak<T, A>)
 - rust-lang#129683 (copysign with sign being a NaN can have non-portable results)
 - rust-lang#129689 (Move `'tcx` lifetime off of impl and onto methods for `CrateMetadataRef`)
 - rust-lang#129695 (Fix path to run clippy on rustdoc)

r? `@ghost`
`@rustbot` modify labels: rollup
workingjubilee added a commit to workingjubilee/rustc that referenced this pull request Aug 29, 2024
copysign with sign being a NaN can have non-portable results

Follow-up to rust-lang#129559.
Cc ``@tgross35`` ``@beetrees``

There's no portable variant we can recommend instead here, is there? Something with a semantics like "if `sign` is a NaN, then return `self` unaltered, otherwise return `self` with the sign changed to that of `sign`"?
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 29, 2024
…kingjubilee

Rollup of 14 pull requests

Successful merges:

 - rust-lang#128192 (rustc_target: Add various aarch64 features)
 - rust-lang#129170 (Add an ability to convert between `Span` and `visit::Location`)
 - rust-lang#129343 (Emit specific message for time<=0.3.35)
 - rust-lang#129378 (Clean up cfg-gating of ProcessPrng extern)
 - rust-lang#129401 (Partially stabilize `feature(new_uninit)`)
 - rust-lang#129467 (derive(SmartPointer): assume pointee from the single generic and better error messages)
 - rust-lang#129494 (format code in tests/ui/threads-sendsync)
 - rust-lang#129617 (Update books)
 - rust-lang#129673 (Add fmt::Debug to sync::Weak<T, A>)
 - rust-lang#129683 (copysign with sign being a NaN can have non-portable results)
 - rust-lang#129689 (Move `'tcx` lifetime off of impl and onto methods for `CrateMetadataRef`)
 - rust-lang#129695 (Fix path to run clippy on rustdoc)
 - rust-lang#129712 (Correct trusty targets to be tier 3)
 - rust-lang#129715 (Update `compiler_builtins` to `0.1.123`)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit dfe66cf into rust-lang:master Aug 29, 2024
6 checks passed
@rustbot rustbot added this to the 1.82.0 milestone Aug 29, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Aug 29, 2024
Rollup merge of rust-lang#129683 - RalfJung:copysign, r=thomcc

copysign with sign being a NaN can have non-portable results

Follow-up to rust-lang#129559.
Cc ```@tgross35``` ```@beetrees```

There's no portable variant we can recommend instead here, is there? Something with a semantics like "if `sign` is a NaN, then return `self` unaltered, otherwise return `self` with the sign changed to that of `sign`"?
@RalfJung RalfJung deleted the copysign branch August 29, 2024 06:43
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.

None yet

6 participants