Skip to content

f64 NaN conversion to f32 maintains sign in Debug, not in Release #120898

Closed
@VoidStarKat

Description

@VoidStarKat

I tried this code:

https://play.rust-lang.org/?version=nightly&mode=release&edition=2021&gist=ca495022488c872fb3addd969e8d705e

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-discussionCategory: Discussion or questions that doesn't represent real issues.T-langRelevant to the language teamT-opsemRelevant to the opsem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions