From 69d3218ca219826a7ee658cf561f013a3e3570a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Nov 2025 14:40:29 +0100 Subject: [PATCH] float::clamp: make treatment of signed zeros unspecified --- library/core/src/num/f128.rs | 9 ++++++++- library/core/src/num/f16.rs | 9 ++++++++- library/core/src/num/f32.rs | 9 ++++++++- library/core/src/num/f64.rs | 9 ++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 2cf06b6d6a35a..377bb4f3a72e3 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1236,7 +1236,8 @@ impl f128 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1253,6 +1254,12 @@ impl f128 { /// assert!((0.0f128).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f128).clamp(-2.0, 1.0) == 1.0); /// assert!((f128::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f128).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f128).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f128).clamp(-0.0, 1.0).is_sign_negative()); /// # } /// ``` #[inline] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 51f803672e5c6..caa787db449c5 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1215,7 +1215,8 @@ impl f16 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1231,6 +1232,12 @@ impl f16 { /// assert!((0.0f16).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f16).clamp(-2.0, 1.0) == 1.0); /// assert!((f16::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f16).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f16).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f16).clamp(-0.0, 1.0).is_sign_negative()); /// # } /// ``` #[inline] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 3070e1dedbe43..6a77c4a477ae5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1395,7 +1395,8 @@ impl f32 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1408,6 +1409,12 @@ impl f32 { /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); /// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f32).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f32).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f32).clamp(-0.0, 1.0).is_sign_negative()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index dc8ccc551b2da..024b90990db5d 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1393,7 +1393,8 @@ impl f64 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1406,6 +1407,12 @@ impl f64 { /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); /// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f64).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f64).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f64).clamp(-0.0, 1.0).is_sign_negative()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")]