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

Add is_signaling_nan() to std::f32 and std::f64 #48825

Closed
icefoxen opened this issue Mar 7, 2018 · 9 comments
Closed

Add is_signaling_nan() to std::f32 and std::f64 #48825

icefoxen opened this issue Mar 7, 2018 · 9 comments
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@icefoxen
Copy link
Contributor

icefoxen commented Mar 7, 2018

Use case: I'm writing a webassembly interpreter. Webassembly specifies that signaling NaN's are invalid. So, I must be able to detect signaling NaN's from my input and return an error when they occur. But, Rust doesn't offer a method for it, so I had to write my own bit-twiddling implementations. This isn't hard, but it seems like it should exist already.

I first brought this up in the num crate, here: rust-num/num#364 , but they can't add it to the Float trait without breaking backwards compatibility, and the exact definition of a signaling NaN is quite architecture-dependent (or at least more so than usual) so it seems like maybe it belongs in std anyway.

For any platform that implements IEEE 754-2008 the following implementations should suffice:

/// Returns whether or not the float is a signaling NaN.
/// A signaling NaN has a format like:
/// `s111 1111 1nxx xxxx xxxx xxxx xxxx xxxx`
/// where the `x`'s represent a non-zero number (zero
/// would be infinity) and `n` is 0.
/// The sign bit `s` may be anything.
///
/// On some old-fashioned platforms (PA-RISC, some MIPS)
/// a signaling NaN is marked by `n=1`, but the 2008 revision of
/// IEEE754 defines it to be `n=0`.
fn f32_is_signaling_nan(f: f32) -> bool {
    let uf: u32 = f.to_bits();
    let signal_bit = 1 << 22;
    let signal_bit_clear = (uf & signal_bit) == 0;
    f32::is_nan(f) && signal_bit_clear
}

/// Same as `f32_is_signaling_nan()` for `f64`'s.
/// The signaling-nan-bit is bit 51 instead of bit 22
fn f64_is_signaling_nan(f: f64) -> bool {
    let uf: u64 = f.to_bits();
    let signal_bit = 1 << 51;
    let signal_bit_clear = (uf & signal_bit) == 0;
    f64::is_nan(f) && signal_bit_clear
}

However, I think LLVM has intrinsics for this too, if I'm looking in the right place: https://llvm.org/doxygen/classllvm_1_1detail_1_1IEEEFloat.html#accc978f15db9b1b2b8e3ac171cbac4e3

I'll make an RFC if people want, but this didn't seem like a "significant change", so here it is. I'll be happy to make a PR for these too if desired.

@sfackler
Copy link
Member

sfackler commented Mar 7, 2018

IIRC we support some targets that aren't IEEE 754-2008 (mips maybe?), so the implementation may need have a bit of cfg(target_arch) applied.

@varkor
Copy link
Member

varkor commented Mar 7, 2018

This issue is related: #10186
I haven't looked too deeply into the changes on LLVM's end in the meantime, but that method does seem like a positive indication.

@Centril Centril added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. C-feature-request Category: A feature request, i.e: not implemented / a PR. labels Mar 7, 2018
@hanna-kruppe
Copy link
Contributor

I wonder whether the platform-dependentness is relevant for this use case. Since wasm is supposed to be platform independent and explicitly follows IEEE 754-2008, wouldn't wasm implementations want to consistently apply the IEEE 754-2008 rules?

I tried to look up what wasm says on the subject but everything I found seems to indicate signaling NaNs are perfectly valid.

@icefoxen
Copy link
Contributor Author

icefoxen commented Mar 7, 2018

Hmmm, it appears that I was misremembering the spec; the part I was thinking of is here:
https://webassembly.github.io/spec/core/exec/numerics.html#floating-point-operations "There is no observable difference between quiet and signalling NaNs." That doesn't really make the need go away though, just changes how I respond to signaling NaN's in input... as far as I can tell I can't currently ensure that the OS won't respond to one with an FPU exception, so I have to convert them to non-signaling NaN's anyway. (edit: though it appears, depending on implementation(?), even loading one into a register may or may not count as "using" and cause an FPE.) We're hitting the limits of my understanding of IEEE754 though, so I don't know the correct way for Rust to handle this sort of thing.

Note: Currently, on x86_64 Debian Linux (Testing), signaling NaN's appear to be ignored. I really hate relying on something like that though when I can't even find where that option in the kernel/whatever is set.

@hanna-kruppe
Copy link
Contributor

hanna-kruppe commented Mar 7, 2018

IEEE specifies a default handling of "exceptions" (which are really nothing at all like exceptions in programming languages, traps in hardware, or anything like that). In the absence of the program explicitly choosing different handling (edit: which Rust doesn't offer, and which LLVM doesn't support yet anyway) in a certain scope, a conforming implementation should always handle the exceptions this way. For invalid operation exceptions (this is the exception signaled by operations on sNaN, but note that many other operations not involving sNaN are also covered by the same exception), this default handling consists of returning a qNaN. Those who have access to the standard can read this up in sections 7 and 8 (edit: 2008 edition).

@icefoxen
Copy link
Contributor Author

icefoxen commented Mar 8, 2018

Oh, lovely. That makes life easy again.

I'm still willing to add methods to the floating point types that recognize a signaling NaN on platforms that support them, if anyone wants them. If not, then this can be closed.

@sfackler
Copy link
Member

sfackler commented Mar 8, 2018

If there's not a compelling use case, I'd err towards leaving them out until we see one.

@est31
Copy link
Member

est31 commented May 7, 2018

Older MIPS platforms treat signaling NaNs exactly the opposite to intel and IEEE754-2008. Newer MIPS standards switched however: first they made IEEE754-2008 NaNs optional and controllable via a flag, then they made that flag read-only and required it to be set, then they mandated IEEE754-2008 for everyone. Issue is though that MIPS is virtually dead, everyone uses ARM now so I couldn't find any CPU that used one of the newer MIPS iterations that have IEEE754-2008 behaviour.

@Enselic
Copy link
Member

Enselic commented Sep 27, 2023

If there's not a compelling use case, I'd err towards leaving them out until we see one.

Triage: Sounds very reasonable. Let's close as won't fix.

@Enselic Enselic closed this as not planned Won't fix, can't repro, duplicate, stale Sep 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants