Skip to content

Commit 553c1bb

Browse files
authored
Rollup merge of rust-lang#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`.
2 parents 06b8c81 + 15290fa commit 553c1bb

File tree

6 files changed

+102
-38
lines changed

6 files changed

+102
-38
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,21 @@ enum MulAddType {
3636

3737
#[derive(Copy, Clone)]
3838
pub(crate) enum MinMax {
39-
/// The IEEE `Minimum` operation - see `f32::minimum` etc
39+
/// The IEEE-2019 `minimum` operation - see `f32::minimum` etc.
4040
/// In particular, `-0.0` is considered smaller than `+0.0` and
4141
/// if either input is NaN, the result is NaN.
4242
Minimum,
43-
/// The IEEE `MinNum` operation - see `f32::min` etc
43+
/// The IEEE-2008 `minNum` operation - see `f32::min` etc.
4444
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
45-
/// and is one argument is NaN, the other one is returned.
45+
/// and if one argument is NaN, the other one is returned.
4646
MinNum,
47-
/// The IEEE `Maximum` operation - see `f32::maximum` etc
47+
/// The IEEE-2019 `maximum` operation - see `f32::maximum` etc.
4848
/// In particular, `-0.0` is considered smaller than `+0.0` and
4949
/// if either input is NaN, the result is NaN.
5050
Maximum,
51-
/// The IEEE `MaxNum` operation - see `f32::max` etc
51+
/// The IEEE-2008 `maxNum` operation - see `f32::max` etc.
5252
/// In particular, if the inputs are `-0.0` and `+0.0`, the result is non-deterministic,
53-
/// and is one argument is NaN, the other one is returned.
53+
/// and if one argument is NaN, the other one is returned.
5454
MaxNum,
5555
}
5656

library/core/src/intrinsics/mod.rs

Lines changed: 88 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2947,61 +2947,77 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
29472947
#[rustc_intrinsic]
29482948
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
29492949

2950-
/// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values.
2950+
/// Returns the minimum of two `f16` values, ignoring NaN.
2951+
///
2952+
/// This behaves like IEEE 754-2008 minNum. In particular:
2953+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
2954+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
29512955
///
29522956
/// Note that, unlike most intrinsics, this is safe to call;
29532957
/// it does not require an `unsafe` block.
29542958
/// Therefore, implementations must not require the user to uphold
29552959
/// any safety invariants.
29562960
///
2957-
/// The stabilized version of this intrinsic is
2958-
/// [`f16::min`]
2961+
/// The stabilized version of this intrinsic is [`f16::min`].
29592962
#[rustc_nounwind]
29602963
#[rustc_intrinsic]
29612964
pub const fn minnumf16(x: f16, y: f16) -> f16;
29622965

2963-
/// Returns the minimum (IEEE 754-2008 minNum) of two `f32` values.
2966+
/// Returns the minimum of two `f32` values, ignoring NaN.
2967+
///
2968+
/// This behaves like IEEE 754-2008 minNum. In particular:
2969+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
2970+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
29642971
///
29652972
/// Note that, unlike most intrinsics, this is safe to call;
29662973
/// it does not require an `unsafe` block.
29672974
/// Therefore, implementations must not require the user to uphold
29682975
/// any safety invariants.
29692976
///
2970-
/// The stabilized version of this intrinsic is
2971-
/// [`f32::min`]
2977+
/// The stabilized version of this intrinsic is [`f32::min`].
29722978
#[rustc_nounwind]
29732979
#[rustc_intrinsic_const_stable_indirect]
29742980
#[rustc_intrinsic]
29752981
pub const fn minnumf32(x: f32, y: f32) -> f32;
29762982

2977-
/// Returns the minimum (IEEE 754-2008 minNum) of two `f64` values.
2983+
/// Returns the minimum of two `f64` values, ignoring NaN.
2984+
///
2985+
/// This behaves like IEEE 754-2008 minNum. In particular:
2986+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
2987+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
29782988
///
29792989
/// Note that, unlike most intrinsics, this is safe to call;
29802990
/// it does not require an `unsafe` block.
29812991
/// Therefore, implementations must not require the user to uphold
29822992
/// any safety invariants.
29832993
///
2984-
/// The stabilized version of this intrinsic is
2985-
/// [`f64::min`]
2994+
/// The stabilized version of this intrinsic is [`f64::min`].
29862995
#[rustc_nounwind]
29872996
#[rustc_intrinsic_const_stable_indirect]
29882997
#[rustc_intrinsic]
29892998
pub const fn minnumf64(x: f64, y: f64) -> f64;
29902999

2991-
/// Returns the minimum (IEEE 754-2008 minNum) of two `f128` values.
3000+
/// Returns the minimum of two `f128` values, ignoring NaN.
3001+
///
3002+
/// This behaves like IEEE 754-2008 minNum. In particular:
3003+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
3004+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
29923005
///
29933006
/// Note that, unlike most intrinsics, this is safe to call;
29943007
/// it does not require an `unsafe` block.
29953008
/// Therefore, implementations must not require the user to uphold
29963009
/// any safety invariants.
29973010
///
2998-
/// The stabilized version of this intrinsic is
2999-
/// [`f128::min`]
3011+
/// The stabilized version of this intrinsic is [`f128::min`].
30003012
#[rustc_nounwind]
30013013
#[rustc_intrinsic]
30023014
pub const fn minnumf128(x: f128, y: f128) -> f128;
30033015

3004-
/// Returns the minimum (IEEE 754-2019 minimum) of two `f16` values.
3016+
/// Returns the minimum of two `f16` values, propagating NaN.
3017+
///
3018+
/// This behaves like IEEE 754-2019 minimum. In particular:
3019+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3020+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
30053021
///
30063022
/// Note that, unlike most intrinsics, this is safe to call;
30073023
/// it does not require an `unsafe` block.
@@ -3022,7 +3038,11 @@ pub const fn minimumf16(x: f16, y: f16) -> f16 {
30223038
}
30233039
}
30243040

3025-
/// Returns the minimum (IEEE 754-2019 minimum) of two `f32` values.
3041+
/// Returns the minimum of two `f32` values, propagating NaN.
3042+
///
3043+
/// This behaves like IEEE 754-2019 minimum. In particular:
3044+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3045+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
30263046
///
30273047
/// Note that, unlike most intrinsics, this is safe to call;
30283048
/// it does not require an `unsafe` block.
@@ -3043,7 +3063,11 @@ pub const fn minimumf32(x: f32, y: f32) -> f32 {
30433063
}
30443064
}
30453065

3046-
/// Returns the minimum (IEEE 754-2019 minimum) of two `f64` values.
3066+
/// Returns the minimum of two `f64` values, propagating NaN.
3067+
///
3068+
/// This behaves like IEEE 754-2019 minimum. In particular:
3069+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3070+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
30473071
///
30483072
/// Note that, unlike most intrinsics, this is safe to call;
30493073
/// it does not require an `unsafe` block.
@@ -3064,7 +3088,11 @@ pub const fn minimumf64(x: f64, y: f64) -> f64 {
30643088
}
30653089
}
30663090

3067-
/// Returns the minimum (IEEE 754-2019 minimum) of two `f128` values.
3091+
/// Returns the minimum of two `f128` values, propagating NaN.
3092+
///
3093+
/// This behaves like IEEE 754-2019 minimum. In particular:
3094+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3095+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
30683096
///
30693097
/// Note that, unlike most intrinsics, this is safe to call;
30703098
/// it does not require an `unsafe` block.
@@ -3085,61 +3113,77 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 {
30853113
}
30863114
}
30873115

3088-
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f16` values.
3116+
/// Returns the maximum of two `f16` values, ignoring NaN.
3117+
///
3118+
/// This behaves like IEEE 754-2008 maxNum. In particular:
3119+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
3120+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
30893121
///
30903122
/// Note that, unlike most intrinsics, this is safe to call;
30913123
/// it does not require an `unsafe` block.
30923124
/// Therefore, implementations must not require the user to uphold
30933125
/// any safety invariants.
30943126
///
3095-
/// The stabilized version of this intrinsic is
3096-
/// [`f16::max`]
3127+
/// The stabilized version of this intrinsic is [`f16::max`].
30973128
#[rustc_nounwind]
30983129
#[rustc_intrinsic]
30993130
pub const fn maxnumf16(x: f16, y: f16) -> f16;
31003131

3101-
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f32` values.
3132+
/// Returns the maximum of two `f32` values, ignoring NaN.
3133+
///
3134+
/// This behaves like IEEE 754-2008 maxNum. In particular:
3135+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
3136+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
31023137
///
31033138
/// Note that, unlike most intrinsics, this is safe to call;
31043139
/// it does not require an `unsafe` block.
31053140
/// Therefore, implementations must not require the user to uphold
31063141
/// any safety invariants.
31073142
///
3108-
/// The stabilized version of this intrinsic is
3109-
/// [`f32::max`]
3143+
/// The stabilized version of this intrinsic is [`f32::max`].
31103144
#[rustc_nounwind]
31113145
#[rustc_intrinsic_const_stable_indirect]
31123146
#[rustc_intrinsic]
31133147
pub const fn maxnumf32(x: f32, y: f32) -> f32;
31143148

3115-
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f64` values.
3149+
/// Returns the maximum of two `f64` values, ignoring NaN.
3150+
///
3151+
/// This behaves like IEEE 754-2008 maxNum. In particular:
3152+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
3153+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
31163154
///
31173155
/// Note that, unlike most intrinsics, this is safe to call;
31183156
/// it does not require an `unsafe` block.
31193157
/// Therefore, implementations must not require the user to uphold
31203158
/// any safety invariants.
31213159
///
3122-
/// The stabilized version of this intrinsic is
3123-
/// [`f64::max`]
3160+
/// The stabilized version of this intrinsic is [`f64::max`].
31243161
#[rustc_nounwind]
31253162
#[rustc_intrinsic_const_stable_indirect]
31263163
#[rustc_intrinsic]
31273164
pub const fn maxnumf64(x: f64, y: f64) -> f64;
31283165

3129-
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f128` values.
3166+
/// Returns the maximum of two `f128` values, ignoring NaN.
3167+
///
3168+
/// This behaves like IEEE 754-2008 maxNum. In particular:
3169+
/// If one of the arguments is NaN, then the other argument is returned. If the inputs compare equal
3170+
/// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
31303171
///
31313172
/// Note that, unlike most intrinsics, this is safe to call;
31323173
/// it does not require an `unsafe` block.
31333174
/// Therefore, implementations must not require the user to uphold
31343175
/// any safety invariants.
31353176
///
3136-
/// The stabilized version of this intrinsic is
3137-
/// [`f128::max`]
3177+
/// The stabilized version of this intrinsic is [`f128::max`].
31383178
#[rustc_nounwind]
31393179
#[rustc_intrinsic]
31403180
pub const fn maxnumf128(x: f128, y: f128) -> f128;
31413181

3142-
/// Returns the maximum (IEEE 754-2019 maximum) of two `f16` values.
3182+
/// Returns the maximum of two `f16` values, propagating NaN.
3183+
///
3184+
/// This behaves like IEEE 754-2019 maximum. In particular:
3185+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3186+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
31433187
///
31443188
/// Note that, unlike most intrinsics, this is safe to call;
31453189
/// it does not require an `unsafe` block.
@@ -3159,7 +3203,11 @@ pub const fn maximumf16(x: f16, y: f16) -> f16 {
31593203
}
31603204
}
31613205

3162-
/// Returns the maximum (IEEE 754-2019 maximum) of two `f32` values.
3206+
/// Returns the maximum of two `f32` values, propagating NaN.
3207+
///
3208+
/// This behaves like IEEE 754-2019 maximum. In particular:
3209+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3210+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
31633211
///
31643212
/// Note that, unlike most intrinsics, this is safe to call;
31653213
/// it does not require an `unsafe` block.
@@ -3179,7 +3227,11 @@ pub const fn maximumf32(x: f32, y: f32) -> f32 {
31793227
}
31803228
}
31813229

3182-
/// Returns the maximum (IEEE 754-2019 maximum) of two `f64` values.
3230+
/// Returns the maximum of two `f64` values, propagating NaN.
3231+
///
3232+
/// This behaves like IEEE 754-2019 maximum. In particular:
3233+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3234+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
31833235
///
31843236
/// Note that, unlike most intrinsics, this is safe to call;
31853237
/// it does not require an `unsafe` block.
@@ -3199,7 +3251,11 @@ pub const fn maximumf64(x: f64, y: f64) -> f64 {
31993251
}
32003252
}
32013253

3202-
/// Returns the maximum (IEEE 754-2019 maximum) of two `f128` values.
3254+
/// Returns the maximum of two `f128` values, propagating NaN.
3255+
///
3256+
/// This behaves like IEEE 754-2019 maximum. In particular:
3257+
/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules.
3258+
/// For this operation, -0.0 is considered to be strictly less than +0.0.
32033259
///
32043260
/// Note that, unlike most intrinsics, this is safe to call;
32053261
/// it does not require an `unsafe` block.

library/core/src/num/f128.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,7 @@ impl f128 {
709709
/// let y = 2.0f128;
710710
///
711711
/// assert_eq!(x.max(y), y);
712+
/// assert_eq!(x.max(f128::NAN), x);
712713
/// # }
713714
/// ```
714715
#[inline]
@@ -736,6 +737,7 @@ impl f128 {
736737
/// let y = 2.0f128;
737738
///
738739
/// assert_eq!(x.min(y), x);
740+
/// assert_eq!(x.min(f128::NAN), x);
739741
/// # }
740742
/// ```
741743
#[inline]

library/core/src/num/f16.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,7 @@ impl f16 {
701701
/// let y = 2.0f16;
702702
///
703703
/// assert_eq!(x.max(y), y);
704+
/// assert_eq!(x.max(f16::NAN), x);
704705
/// # }
705706
/// ```
706707
#[inline]
@@ -727,6 +728,7 @@ impl f16 {
727728
/// let y = 2.0f16;
728729
///
729730
/// assert_eq!(x.min(y), x);
731+
/// assert_eq!(x.min(f16::NAN), x);
730732
/// # }
731733
/// ```
732734
#[inline]

library/core/src/num/f32.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,7 @@ impl f32 {
908908
/// let y = 2.0f32;
909909
///
910910
/// assert_eq!(x.max(y), y);
911+
/// assert_eq!(x.max(f32::NAN), x);
911912
/// ```
912913
#[must_use = "this returns the result of the comparison, without modifying either input"]
913914
#[stable(feature = "rust1", since = "1.0.0")]
@@ -930,6 +931,7 @@ impl f32 {
930931
/// let y = 2.0f32;
931932
///
932933
/// assert_eq!(x.min(y), x);
934+
/// assert_eq!(x.min(f32::NAN), x);
933935
/// ```
934936
#[must_use = "this returns the result of the comparison, without modifying either input"]
935937
#[stable(feature = "rust1", since = "1.0.0")]

library/core/src/num/f64.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,7 @@ impl f64 {
926926
/// let y = 2.0_f64;
927927
///
928928
/// assert_eq!(x.max(y), y);
929+
/// assert_eq!(x.max(f64::NAN), x);
929930
/// ```
930931
#[must_use = "this returns the result of the comparison, without modifying either input"]
931932
#[stable(feature = "rust1", since = "1.0.0")]
@@ -948,6 +949,7 @@ impl f64 {
948949
/// let y = 2.0_f64;
949950
///
950951
/// assert_eq!(x.min(y), x);
952+
/// assert_eq!(x.min(f64::NAN), x);
951953
/// ```
952954
#[must_use = "this returns the result of the comparison, without modifying either input"]
953955
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)