Rollup merge of #149239 - RalfJung:float-intrinsics, r=tgross35

clarify float min/max behavios for NaNs and signed zeros

The first comment is internal, it only documents the intrinsics to more clearly say what they do.
This makes the currently implemented semantics more explicit, so one does not have to go look for the publicly exposed version of the operation to figure out what exactly should happen.

The second commit adds a NaN test to the doc comment for `min`/`max`, which matches what we already have for `minimum`/`maximum`.
This commit is contained in:
Stuart Cook 2025-11-27 12:36:52 +11:00 committed by GitHub
commit df6f24cc51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 102 additions and 38 deletions

View file

@ -36,21 +36,21 @@ enum MulAddType {
#[derive(Copy, Clone)]
pub(crate) enum MinMax {
/// The IEEE `Minimum` operation - see `f32::minimum` etc
/// The IEEE-2019 `minimum` operation - see `f32::minimum` etc.
/// In particular, `-0.0` is considered smaller than `+0.0` and
/// if either input is NaN, the result is NaN.
Minimum,
/// The IEEE `MinNum` operation - see `f32::min` etc
/// The IEEE-2008 `minNum` operation - see `f32::min` etc.
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
/// and is one argument is NaN, the other one is returned.
/// and if one argument is NaN, the other one is returned.
MinNum,
/// The IEEE `Maximum` operation - see `f32::maximum` etc
/// The IEEE-2019 `maximum` operation - see `f32::maximum` etc.
/// In particular, `-0.0` is considered smaller than `+0.0` and
/// if either input is NaN, the result is NaN.
Maximum,
/// The IEEE `MaxNum` operation - see `f32::max` etc
/// The IEEE-2008 `maxNum` operation - see `f32::max` etc.
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
/// and is one argument is NaN, the other one is returned.
/// and if one argument is NaN, the other one is returned.
MaxNum,
}

View file

@ -2947,61 +2947,77 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
#[rustc_intrinsic]
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
/// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values.
/// Returns the minimum of two `f16` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 minNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f16::min`]
/// The stabilized version of this intrinsic is [`f16::min`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub const fn minnumf16(x: f16, y: f16) -> f16;
/// Returns the minimum (IEEE 754-2008 minNum) of two `f32` values.
/// Returns the minimum of two `f32` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 minNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f32::min`]
/// The stabilized version of this intrinsic is [`f32::min`].
#[rustc_nounwind]
#[rustc_intrinsic_const_stable_indirect]
#[rustc_intrinsic]
pub const fn minnumf32(x: f32, y: f32) -> f32;
/// Returns the minimum (IEEE 754-2008 minNum) of two `f64` values.
/// Returns the minimum of two `f64` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 minNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f64::min`]
/// The stabilized version of this intrinsic is [`f64::min`].
#[rustc_nounwind]
#[rustc_intrinsic_const_stable_indirect]
#[rustc_intrinsic]
pub const fn minnumf64(x: f64, y: f64) -> f64;
/// Returns the minimum (IEEE 754-2008 minNum) of two `f128` values.
/// Returns the minimum of two `f128` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 minNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f128::min`]
/// The stabilized version of this intrinsic is [`f128::min`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub const fn minnumf128(x: f128, y: f128) -> f128;
/// Returns the minimum (IEEE 754-2019 minimum) of two `f16` values.
/// Returns the minimum of two `f16` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 minimum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
@ -3022,7 +3038,11 @@ pub const fn minimumf16(x: f16, y: f16) -> f16 {
}
}
/// Returns the minimum (IEEE 754-2019 minimum) of two `f32` values.
/// Returns the minimum of two `f32` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 minimum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
@ -3043,7 +3063,11 @@ pub const fn minimumf32(x: f32, y: f32) -> f32 {
}
}
/// Returns the minimum (IEEE 754-2019 minimum) of two `f64` values.
/// Returns the minimum of two `f64` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 minimum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
@ -3064,7 +3088,11 @@ pub const fn minimumf64(x: f64, y: f64) -> f64 {
}
}
/// Returns the minimum (IEEE 754-2019 minimum) of two `f128` values.
/// Returns the minimum of two `f128` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 minimum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
@ -3085,61 +3113,77 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 {
}
}
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f16` values.
/// Returns the maximum of two `f16` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 maxNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f16::max`]
/// The stabilized version of this intrinsic is [`f16::max`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub const fn maxnumf16(x: f16, y: f16) -> f16;
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f32` values.
/// Returns the maximum of two `f32` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 maxNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f32::max`]
/// The stabilized version of this intrinsic is [`f32::max`].
#[rustc_nounwind]
#[rustc_intrinsic_const_stable_indirect]
#[rustc_intrinsic]
pub const fn maxnumf32(x: f32, y: f32) -> f32;
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f64` values.
/// Returns the maximum of two `f64` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 maxNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f64::max`]
/// The stabilized version of this intrinsic is [`f64::max`].
#[rustc_nounwind]
#[rustc_intrinsic_const_stable_indirect]
#[rustc_intrinsic]
pub const fn maxnumf64(x: f64, y: f64) -> f64;
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f128` values.
/// Returns the maximum of two `f128` values, ignoring NaN.
///
/// This behaves like IEEE 754-2008 maxNum. In particular:
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
/// The stabilized version of this intrinsic is
/// [`f128::max`]
/// The stabilized version of this intrinsic is [`f128::max`].
#[rustc_nounwind]
#[rustc_intrinsic]
pub const fn maxnumf128(x: f128, y: f128) -> f128;
/// Returns the maximum (IEEE 754-2019 maximum) of two `f16` values.
/// Returns the maximum of two `f16` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 maximum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
@ -3159,7 +3203,11 @@ pub const fn maximumf16(x: f16, y: f16) -> f16 {
}
}
/// Returns the maximum (IEEE 754-2019 maximum) of two `f32` values.
/// Returns the maximum of two `f32` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 maximum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
@ -3179,7 +3227,11 @@ pub const fn maximumf32(x: f32, y: f32) -> f32 {
}
}
/// Returns the maximum (IEEE 754-2019 maximum) of two `f64` values.
/// Returns the maximum of two `f64` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 maximum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
@ -3199,7 +3251,11 @@ pub const fn maximumf64(x: f64, y: f64) -> f64 {
}
}
/// Returns the maximum (IEEE 754-2019 maximum) of two `f128` values.
/// Returns the maximum of two `f128` values, propagating NaN.
///
/// This behaves like IEEE 754-2019 maximum. In particular:
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
/// For this operation, -0.0 is considered to be strictly less than +0.0.
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.

View file

@ -709,6 +709,7 @@ impl f128 {
/// let y = 2.0f128;
///
/// assert_eq!(x.max(y), y);
/// assert_eq!(x.max(f128::NAN), x);
/// # }
/// ```
#[inline]
@ -736,6 +737,7 @@ impl f128 {
/// let y = 2.0f128;
///
/// assert_eq!(x.min(y), x);
/// assert_eq!(x.min(f128::NAN), x);
/// # }
/// ```
#[inline]

View file

@ -701,6 +701,7 @@ impl f16 {
/// let y = 2.0f16;
///
/// assert_eq!(x.max(y), y);
/// assert_eq!(x.max(f16::NAN), x);
/// # }
/// ```
#[inline]
@ -727,6 +728,7 @@ impl f16 {
/// let y = 2.0f16;
///
/// assert_eq!(x.min(y), x);
/// assert_eq!(x.min(f16::NAN), x);
/// # }
/// ```
#[inline]

View file

@ -908,6 +908,7 @@ impl f32 {
/// let y = 2.0f32;
///
/// assert_eq!(x.max(y), y);
/// assert_eq!(x.max(f32::NAN), x);
/// ```
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
@ -930,6 +931,7 @@ impl f32 {
/// let y = 2.0f32;
///
/// assert_eq!(x.min(y), x);
/// assert_eq!(x.min(f32::NAN), x);
/// ```
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -926,6 +926,7 @@ impl f64 {
/// let y = 2.0_f64;
///
/// assert_eq!(x.max(y), y);
/// assert_eq!(x.max(f64::NAN), x);
/// ```
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
@ -948,6 +949,7 @@ impl f64 {
/// let y = 2.0_f64;
///
/// assert_eq!(x.min(y), x);
/// assert_eq!(x.min(f64::NAN), x);
/// ```
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]