Rust: NaN > NaN returns true

Created on 16 May 2018  路  10Comments  路  Source: rust-lang/rust

The following tests do not pass for me, but I think they should, as comparisons with NaN should always simply evaluate to false:

#[test]
fn test_zero_zero() {
    assert_eq!(0.0/0.0 < 0.0/0.0, false);
    assert_eq!(0.0/0.0 > 0.0/0.0, false);
}

#[test]
fn test_nan_nan() {
    assert_eq!(std::f64::NAN < std::f64::NAN, false);
    assert_eq!(std::f64::NAN > std::f64::NAN, false);
}

fn main() {
    println!("Hello, world!");
}

I get this result on both debug and release builds. I'm on an x86_64 running Linux, rustc 1.27.0-nightly (f0fdaba04 2018-05-15).

A-const-eval C-bug I-unsound 馃挜 P-high T-compiler regression-from-stable-to-stable

Most helpful comment

Bisection between c83fa5d91c3b16459ab7b87c48ed18bd059a23af...097efa9a998d4f3a4aee3af126e8f8a9eba1ae07 gives #46882 as the regression PR, as expected.

All 10 comments

Playground link for this test.

https://play.rust-lang.org/?gist=4d6f7f54553b065615caac65b3cb6222&version=nightly&mode=debug

Affects both debug and release, Nightly and Stable.

Playground:

fn main() {
    let operator = std::f64::NAN > std::f64::NAN;
    let method = std::f64::NAN.gt(&std::f64::NAN);
    println!("{} {}", operator, method); // false false
    assert_eq!(operator, method); // doesn't fail
    assert_eq!(std::f64::NAN > std::f64::NAN, std::f64::NAN.gt(&std::f64::NAN)); // fails
}

~I think this is an issue with assert_eq! rather than the floating-point comparisons, but I haven't dug into it yet.~

This seems to be a regression introduced by 1.26.

Reduced, related to rvalue promotion I guess.

extern { fn abort() -> !; }

fn main() {
    let f = &(std::f64::NAN > std::f64::NAN);
    if *f {
        unsafe { abort(); }
    }
}

Edit: Or maybe a bug in Miri (cc @oli-obk)

extern { fn abort() -> !; }

static B: bool = std::f64::NAN > std::f64::NAN;

fn main() {
    if B {
        unsafe { abort(); }
    }
}

Bisection between c83fa5d91c3b16459ab7b87c48ed18bd059a23af...097efa9a998d4f3a4aee3af126e8f8a9eba1ae07 gives #46882 as the regression PR, as expected.

I guess this logic, which I blindly copied, was never correct to begin with:

https://github.com/rust-lang/rust/blob/master/src/librustc_mir/interpret/operator.rs#L188

I think this is how old const eval did it, and we didn't want to regress that. cc @eddyb

https://github.com/rust-lang/rust/commit/40b118cf4767413f7676c97296c222167604485b#diff-580fb7d0b0ede57fb2ce24a5dd33910cL50

Has the comment about existing bad behaviour.

@oli-obk The old logic used unwrap, meaning NaN > NaN would just ICE (?). I think we can safely replace them directly as PrimVal::from_bool(l > r) etc.

Edit: 馃 The unwrap is in https://github.com/rust-lang/rust/commit/40b118cf4767413f7676c97296c222167604485b#diff-e847a6da94440f7bf6783206efe4275bL138

The incorrect behavior mentioned in https://github.com/rust-lang/rust/issues/50811#issuecomment-389644453 was this:

let x: [u8; (std::f64::NAN > std::f64::NAN) as usize] = [1];

If we fix the float comparison behavior, this code will no longer compile. But I think this is clearly a bug fix and breaking code like this is acceptable.

Was this page helpful?
0 / 5 - 0 ratings