Closed
Description
I tried this code:
fn main() {
{
// This code works in both Debug & Release
let nan64 = f64::from_bits(0x7FF0_0000_0000_0001u64);
let nan32_from_64 = nan64 as f32;
assert!(nan64.is_nan() && nan64.is_sign_positive());
assert!(nan32_from_64.is_nan() && nan32_from_64.is_sign_positive());
}
{
// Runs without errors in Debug. Fails in Release.
let neg_nan64 = f64::from_bits(0xFFF0_0000_0000_0001u64);
let neg_nan32_from_64 = neg_nan64 as f32;
assert!(neg_nan64.is_nan() && neg_nan64.is_sign_negative());
assert!(neg_nan32_from_64.is_nan() && neg_nan32_from_64.is_sign_negative());
}
}
I expected to see this happen:
f64
to f32
conversion of a NaN value has the same behavior between Debug and Release mode. Hardware may or may not be preserving sign of NaN casts, so this may differ on different hardware with different standards support, but same behavior between compile modes would be expected
Instead, this happened:
Casting a negative-signed NaN f64
to a f32
maintains the negative-sign in Debug mode but not in Release mode. This behavior has been occurring since 1.75 according to VoidStarKat/half-rs#103 and still exists in nightly. Interestingly, when using miri, the float sign changes in both debug & release, but for positive-signed floats.
Meta
rustc --version --verbose
:
rustc 1.76.0 (07dca489a 2024-02-04)
binary: rustc
commit-hash: 07dca489ac2d933c78d3c5158e3f43beefeb02ce
commit-date: 2024-02-04
host: x86_64-unknown-linux-gnu
release: 1.76.0
LLVM version: 17.0.6
Backtrace
Running `target/release/playground`
thread 'main' panicked at src/main.rs:17:9:
assertion failed: neg_nan32_from_64.is_nan() && neg_nan32_from_64.is_sign_negative()
stack backtrace:
0: rust_begin_unwind
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
1: core::panicking::panic_fmt
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
2: core::panicking::panic
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:144:5
3: playground::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.