about summary refs log tree commit diff
path: root/library/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src')
-rw-r--r--library/core/src/intrinsics/simd.rs2
-rw-r--r--library/core/src/num/f128.rs30
-rw-r--r--library/core/src/num/f16.rs30
-rw-r--r--library/core/src/num/f32.rs14
-rw-r--r--library/core/src/num/f64.rs14
-rw-r--r--library/core/src/primitive_docs.rs78
6 files changed, 131 insertions, 37 deletions
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 221724d7b4a..59828198099 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -232,7 +232,7 @@ extern "rust-intrinsic" {
     ///
     /// `T` must be a vector.
     ///
-    /// `U` must be a **const** array of `i32`s. This means it must either refer to a named
+    /// `U` must be a **const** array or vector of `u32`s. This means it must either refer to a named
     /// const or be given as an inline const expression (`const { ... }`).
     ///
     /// `V` must be a vector with the same element type as `T` and the same length as `U`.
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 38e69e7641a..d4236e47bfe 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -454,11 +454,14 @@ impl f128 {
     }
 
     /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
-    /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
-    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
-    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
-    /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
-    /// See [explanation of NaN as a special value](f128) for more info.
+    /// positive sign bit and positive infinity.
+    ///
+    /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
+    /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
+    /// conserved over arithmetic operations, the result of `is_sign_positive` on
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == 1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// #![feature(f128)]
@@ -477,11 +480,14 @@ impl f128 {
     }
 
     /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
-    /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
-    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
-    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
-    /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
-    /// See [explanation of NaN as a special value](f128) for more info.
+    /// negative sign bit and negative infinity.
+    ///
+    /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
+    /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
+    /// conserved over arithmetic operations, the result of `is_sign_negative` on
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == -1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// #![feature(f128)]
@@ -750,7 +756,7 @@ impl f128 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
@@ -791,7 +797,7 @@ impl f128 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index bb0cc1c60ba..1e2f841aca7 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -464,11 +464,14 @@ impl f16 {
     }
 
     /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
-    /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
-    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
-    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
-    /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
-    /// See [explanation of NaN as a special value](f16) for more info.
+    /// positive sign bit and positive infinity.
+    ///
+    /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
+    /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
+    /// conserved over arithmetic operations, the result of `is_sign_positive` on
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == 1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// #![feature(f16)]
@@ -490,11 +493,14 @@ impl f16 {
     }
 
     /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
-    /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
-    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
-    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
-    /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
-    /// See [explanation of NaN as a special value](f16) for more info.
+    /// negative sign bit and negative infinity.
+    ///
+    /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
+    /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
+    /// conserved over arithmetic operations, the result of `is_sign_negative` on
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == -1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// #![feature(f16)]
@@ -762,7 +768,7 @@ impl f16 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
@@ -802,7 +808,7 @@ impl f16 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
     // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 719727e2f1e..c1adcc753f2 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -700,8 +700,9 @@ impl f32 {
     /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
     /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
     /// conserved over arithmetic operations, the result of `is_sign_positive` on
-    /// a NaN might produce an unexpected result in some cases. See [explanation
-    /// of NaN as a special value](f32) for more info.
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == 1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// let f = 7.0_f32;
@@ -724,8 +725,9 @@ impl f32 {
     /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
     /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
     /// conserved over arithmetic operations, the result of `is_sign_negative` on
-    /// a NaN might produce an unexpected result in some cases. See [explanation
-    /// of NaN as a special value](f32) for more info.
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == -1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// let f = 7.0f32;
@@ -954,7 +956,7 @@ impl f32 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
@@ -989,7 +991,7 @@ impl f32 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 85eb152ad1f..e6406771ad3 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -695,8 +695,9 @@ impl f64 {
     /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
     /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
     /// conserved over arithmetic operations, the result of `is_sign_positive` on
-    /// a NaN might produce an unexpected result in some cases. See [explanation
-    /// of NaN as a special value](f32) for more info.
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == 1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// let f = 7.0_f64;
@@ -728,8 +729,9 @@ impl f64 {
     /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of
     /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are
     /// conserved over arithmetic operations, the result of `is_sign_negative` on
-    /// a NaN might produce an unexpected result in some cases. See [explanation
-    /// of NaN as a special value](f32) for more info.
+    /// a NaN might produce an unexpected or non-portable result. See the [specification
+    /// of NaN bit patterns](f32#nan-bit-patterns) for more info. Use `self.signum() == -1.0`
+    /// if you need fully portable behavior (will return `false` for all NaNs).
     ///
     /// ```
     /// let f = 7.0_f64;
@@ -968,7 +970,7 @@ impl f64 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
@@ -1003,7 +1005,7 @@ impl f64 {
     /// Note that this follows the semantics specified in IEEE 754-2019.
     ///
     /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
-    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
+    /// operand is conserved; see the [specification of NaN bit patterns](f32#nan-bit-patterns) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 09ebef89fb0..7f35c7789e2 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1190,6 +1190,11 @@ mod prim_f16 {}
 ///     portable or even fully deterministic! This means that there may be some
 ///     surprising results upon inspecting the bit patterns,
 ///     as the same calculations might produce NaNs with different bit patterns.
+///     This also affects the sign of the NaN: checking `is_sign_positive` or `is_sign_negative` on
+///     a NaN is the most common way to run into these surprising results.
+///     (Checking `x >= 0.0` or `x <= 0.0` avoids those surprises, but also how negative/positive
+///     zero are treated.)
+///     See the section below for what exactly is guaranteed about the bit pattern of a NaN.
 ///
 /// When a primitive operation (addition, subtraction, multiplication, or
 /// division) is performed on this type, the result is rounded according to the
@@ -1211,6 +1216,79 @@ mod prim_f16 {}
 /// *[See also the `std::f32::consts` module](crate::f32::consts).*
 ///
 /// [wikipedia]: https://en.wikipedia.org/wiki/Single-precision_floating-point_format
+///
+/// # NaN bit patterns
+///
+/// This section defines the possible NaN bit patterns returned by non-"bitwise" floating point
+/// operations. The bitwise operations are unary `-`, `abs`, `copysign`; those are guaranteed to
+/// exactly preserve the bit pattern of their input except for possibly changing the sign bit.
+///
+/// A floating-point NaN value consists of:
+/// - a sign bit
+/// - a quiet/signaling bit
+/// - a payload, which makes up the rest of the significand (i.e., the mantissa) except for the
+///   quiet/signaling bit.
+///
+/// Rust assumes that the quiet/signaling bit being set to `1` indicates a quiet NaN (QNaN), and a
+/// value of `0` indicates a signaling NaN (SNaN). In the following we will hence just call it the
+/// "quiet bit".
+///
+/// The following rules apply when a NaN value is returned: the result has a non-deterministic sign.
+/// The quiet bit and payload are non-deterministically chosen from the following set of options:
+///
+/// - **Preferred NaN**: The quiet bit is set and the payload is all-zero.
+/// - **Quieting NaN propagation**: The quiet bit is set and the payload is copied from any input
+///   operand that is a NaN. If the inputs and outputs do not have the same payload size (i.e., for
+///   `as` casts), then
+///   - If the output is smaller than the input, low-order bits of the payload get dropped.
+///   - If the output is larger than the input, the payload gets filled up with 0s in the low-order
+///     bits.
+/// - **Unchanged NaN propagation**: The quiet bit and payload are copied from any input operand
+///   that is a NaN. If the inputs and outputs do not have the same size (i.e., for `as` casts), the
+///   same rules as for "quieting NaN propagation" apply, with one caveat: if the output is smaller
+///   than the input, droppig the low-order bits may result in a payload of 0; a payload of 0 is not
+///   possible with a signaling NaN (the all-0 significand encodes an infinity) so unchanged NaN
+///   propagation cannot occur with some inputs.
+/// - **Target-specific NaN**: The quiet bit is set and the payload is picked from a target-specific
+///   set of "extra" possible NaN payloads. The set can depend on the input operand values.
+///   See the table below for the concrete NaNs this set contains on various targets.
+///
+/// In particular, if all input NaNs are quiet (or if there are no input NaNs), then the output NaN
+/// is definitely quiet. Signaling NaN outputs can only occur if they are provided as an input
+/// value. Similarly, if all input NaNs are preferred (or if there are no input NaNs) and the target
+/// does not have any "extra" NaN payloads, then the output NaN is guaranteed to be preferred.
+///
+/// The non-deterministic choice happens when the operation is executed; i.e., the result of a
+/// NaN-producing floating point operation is a stable bit pattern (looking at these bits multiple
+/// times will yield consistent results), but running the same operation twice with the same inputs
+/// can produce different results.
+///
+/// These guarantees are neither stronger nor weaker than those of IEEE 754: IEEE 754 guarantees
+/// that an operation never returns a signaling NaN, whereas it is possible for operations like
+/// `SNAN * 1.0` to return a signaling NaN in Rust. Conversely, IEEE 754 makes no statement at all
+/// about which quiet NaN is returned, whereas Rust restricts the set of possible results to the
+/// ones listed above.
+///
+/// Unless noted otherwise, the same rules also apply to NaNs returned by other library functions
+/// (e.g. `min`, `minimum`, `max`, `maximum`); other aspects of their semantics and which IEEE 754
+/// operation they correspond to are documented with the respective functions.
+///
+/// When a floating-point operation is executed in `const` context, the same rules apply: no
+/// guarantee is made about which of the NaN bit patterns described above will be returned. The
+/// result does not have to match what happens when executing the same code at runtime, and the
+/// result can vary depending on factors such as compiler version and flags.
+///
+/// ### Target-specific "extra" NaN values
+// FIXME: Is there a better place to put this?
+///
+/// | `target_arch` | Extra payloads possible on this platform |
+/// |---------------|---------|
+/// | `x86`, `x86_64`, `arm`, `aarch64`, `riscv32`, `riscv64` | None |
+/// | `sparc`, `sparc64` | The all-one payload |
+/// | `wasm32`, `wasm64` | If all input NaNs are quiet with all-zero payload: None.<br> Otherwise: all possible payloads. |
+///
+/// For targets not in this table, all payloads are possible.
+
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_f32 {}