Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,38 @@ impl f128 {
self
}

/// Clamps this number to a symmetric range centered around zero.
///
/// The method clamps the number's magnitude (absolute value) to be at most `limit`.
///
/// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more
/// explicit about the intent.
///
/// # Panics
///
/// Panics if `limit` is negative or NaN, as this indicates a logic error.
///
/// # Examples
///
/// ```
/// #![feature(f128)]
/// #![feature(clamp_magnitude)]
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// assert_eq!(5.0f128.clamp_magnitude(3.0), 3.0);
/// assert_eq!((-5.0f128).clamp_magnitude(3.0), -3.0);
/// assert_eq!(2.0f128.clamp_magnitude(3.0), 2.0);
/// assert_eq!((-2.0f128).clamp_magnitude(3.0), -2.0);
/// # }
/// ```
#[inline]
#[unstable(feature = "clamp_magnitude", issue = "148519")]
#[must_use = "this returns the clamped value and does not modify the original"]
pub fn clamp_magnitude(self, limit: f128) -> f128 {
assert!(limit >= 0.0, "limit must be non-negative");
let limit = limit.abs(); // Canonicalises -0.0 to 0.0
self.clamp(-limit, limit)
}

/// Computes the absolute value of `self`.
///
/// This function always returns the precise result.
Expand Down
32 changes: 32 additions & 0 deletions library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1254,6 +1254,38 @@ impl f16 {
self
}

/// Clamps this number to a symmetric range centered around zero.
///
/// The method clamps the number's magnitude (absolute value) to be at most `limit`.
///
/// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more
/// explicit about the intent.
///
/// # Panics
///
/// Panics if `limit` is negative or NaN, as this indicates a logic error.
///
/// # Examples
///
/// ```
/// #![feature(f16)]
/// #![feature(clamp_magnitude)]
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// assert_eq!(5.0f16.clamp_magnitude(3.0), 3.0);
/// assert_eq!((-5.0f16).clamp_magnitude(3.0), -3.0);
/// assert_eq!(2.0f16.clamp_magnitude(3.0), 2.0);
/// assert_eq!((-2.0f16).clamp_magnitude(3.0), -2.0);
/// # }
/// ```
#[inline]
#[unstable(feature = "clamp_magnitude", issue = "148519")]
#[must_use = "this returns the clamped value and does not modify the original"]
pub fn clamp_magnitude(self, limit: f16) -> f16 {
assert!(limit >= 0.0, "limit must be non-negative");
let limit = limit.abs(); // Canonicalises -0.0 to 0.0
self.clamp(-limit, limit)
}

/// Computes the absolute value of `self`.
///
/// This function always returns the precise result.
Expand Down
29 changes: 29 additions & 0 deletions library/core/src/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,35 @@ impl f32 {
self
}

/// Clamps this number to a symmetric range centered around zero.
///
/// The method clamps the number's magnitude (absolute value) to be at most `limit`.
///
/// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more
/// explicit about the intent.
///
/// # Panics
///
/// Panics if `limit` is negative or NaN, as this indicates a logic error.
///
/// # Examples
///
/// ```
/// #![feature(clamp_magnitude)]
/// assert_eq!(5.0f32.clamp_magnitude(3.0), 3.0);
/// assert_eq!((-5.0f32).clamp_magnitude(3.0), -3.0);
/// assert_eq!(2.0f32.clamp_magnitude(3.0), 2.0);
/// assert_eq!((-2.0f32).clamp_magnitude(3.0), -2.0);
/// ```
#[must_use = "this returns the clamped value and does not modify the original"]
#[unstable(feature = "clamp_magnitude", issue = "148519")]
#[inline]
pub fn clamp_magnitude(self, limit: f32) -> f32 {
assert!(limit >= 0.0, "limit must be non-negative");
let limit = limit.abs(); // Canonicalises -0.0 to 0.0
self.clamp(-limit, limit)
}

/// Computes the absolute value of `self`.
///
/// This function always returns the precise result.
Expand Down
29 changes: 29 additions & 0 deletions library/core/src/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,35 @@ impl f64 {
self
}

/// Clamps this number to a symmetric range centered around zero.
///
/// The method clamps the number's magnitude (absolute value) to be at most `limit`.
///
/// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more
/// explicit about the intent.
///
/// # Panics
///
/// Panics if `limit` is negative or NaN, as this indicates a logic error.
///
/// # Examples
///
/// ```
/// #![feature(clamp_magnitude)]
/// assert_eq!(5.0f64.clamp_magnitude(3.0), 3.0);
/// assert_eq!((-5.0f64).clamp_magnitude(3.0), -3.0);
/// assert_eq!(2.0f64.clamp_magnitude(3.0), 2.0);
/// assert_eq!((-2.0f64).clamp_magnitude(3.0), -2.0);
/// ```
#[must_use = "this returns the clamped value and does not modify the original"]
#[unstable(feature = "clamp_magnitude", issue = "148519")]
#[inline]
pub fn clamp_magnitude(self, limit: f64) -> f64 {
assert!(limit >= 0.0, "limit must be non-negative");
let limit = limit.abs(); // Canonicalises -0.0 to 0.0
self.clamp(-limit, limit)
}

/// Computes the absolute value of `self`.
///
/// This function always returns the precise result.
Expand Down
27 changes: 27 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3855,5 +3855,32 @@ macro_rules! int_impl {
pub const fn max_value() -> Self {
Self::MAX
}

/// Clamps this number to a symmetric range centred around zero.
///
/// The method clamps the number's magnitude (absolute value) to be at most `limit`.
///
/// This is functionally equivalent to `self.clamp(-limit, limit)`, but is more
/// explicit about the intent.
///
/// # Examples
///
/// ```
/// #![feature(clamp_magnitude)]
#[doc = concat!("assert_eq!(120", stringify!($SelfT), ".clamp_magnitude(100), 100);")]
#[doc = concat!("assert_eq!(-120", stringify!($SelfT), ".clamp_magnitude(100), -100);")]
#[doc = concat!("assert_eq!(80", stringify!($SelfT), ".clamp_magnitude(100), 80);")]
#[doc = concat!("assert_eq!(-80", stringify!($SelfT), ".clamp_magnitude(100), -80);")]
/// ```
#[must_use = "this returns the clamped value and does not modify the original"]
#[unstable(feature = "clamp_magnitude", issue = "148519")]
#[inline]
pub fn clamp_magnitude(self, limit: $UnsignedT) -> Self {
if let Ok(limit) = core::convert::TryInto::<$SelfT>::try_into(limit) {
self.clamp(-limit, limit)
} else {
self
}
}
}
}
1 change: 1 addition & 0 deletions library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#![feature(cfg_target_has_reliable_f16_f128)]
#![feature(char_internals)]
#![feature(char_max_len)]
#![feature(clamp_magnitude)]
#![feature(clone_to_uninit)]
#![feature(const_cell_traits)]
#![feature(const_cmp)]
Expand Down
139 changes: 139 additions & 0 deletions library/coretests/tests/num/clamp_magnitude.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
macro_rules! check_int_clamp {
($t:ty, $ut:ty) => {
let min = <$t>::MIN;
let max = <$t>::MAX;
let max_u = <$ut>::MAX;

// Basic clamping
assert_eq!((100 as $t).clamp_magnitude(50), 50);
assert_eq!((-100 as $t).clamp_magnitude(50), -50);
assert_eq!((30 as $t).clamp_magnitude(50), 30);
assert_eq!((-30 as $t).clamp_magnitude(50), -30);

// Exact boundary
assert_eq!((50 as $t).clamp_magnitude(50), 50);
assert_eq!((-50 as $t).clamp_magnitude(50), -50);

// Zero cases
assert_eq!((0 as $t).clamp_magnitude(100), 0);
assert_eq!((0 as $t).clamp_magnitude(0), 0);
assert_eq!((100 as $t).clamp_magnitude(0), 0);
assert_eq!((-100 as $t).clamp_magnitude(0), 0);

// MIN/MAX values
// Symmetric range [-MAX, MAX]
assert_eq!(max.clamp_magnitude(max as $ut), max);
assert_eq!(min.clamp_magnitude(max as $ut), -max);

// Full range (limit covers MIN)
let min_abs = min.unsigned_abs();
assert_eq!(min.clamp_magnitude(min_abs), min);

// Limit larger than type max (uN > iN::MAX)
assert_eq!(max.clamp_magnitude(max_u), max);
assert_eq!(min.clamp_magnitude(max_u), min);
};
}

#[test]
fn test_clamp_magnitude_i8() {
check_int_clamp!(i8, u8);
}

#[test]
fn test_clamp_magnitude_i16() {
check_int_clamp!(i16, u16);
}

#[test]
fn test_clamp_magnitude_i32() {
check_int_clamp!(i32, u32);
}

#[test]
fn test_clamp_magnitude_i64() {
check_int_clamp!(i64, u64);
}

#[test]
fn test_clamp_magnitude_i128() {
check_int_clamp!(i128, u128);
}

#[test]
fn test_clamp_magnitude_isize() {
check_int_clamp!(isize, usize);
}

macro_rules! check_float_clamp {
($t:ty) => {
// Basic clamping
assert_eq!((5.0 as $t).clamp_magnitude(3.0), 3.0);
assert_eq!((-5.0 as $t).clamp_magnitude(3.0), -3.0);
assert_eq!((2.0 as $t).clamp_magnitude(3.0), 2.0);
assert_eq!((-2.0 as $t).clamp_magnitude(3.0), -2.0);

// Exact boundary
assert_eq!((3.0 as $t).clamp_magnitude(3.0), 3.0);
assert_eq!((-3.0 as $t).clamp_magnitude(3.0), -3.0);

// Zero cases
assert_eq!((0.0 as $t).clamp_magnitude(1.0), 0.0);
assert_eq!((-0.0 as $t).clamp_magnitude(1.0), 0.0);
assert_eq!((5.0 as $t).clamp_magnitude(0.0), 0.0);
assert_eq!((-5.0 as $t).clamp_magnitude(0.0), 0.0);

// Special values - Infinity
let inf = <$t>::INFINITY;
let neg_inf = <$t>::NEG_INFINITY;
assert_eq!(inf.clamp_magnitude(100.0), 100.0);
assert_eq!(neg_inf.clamp_magnitude(100.0), -100.0);
assert_eq!(inf.clamp_magnitude(inf), inf);

// Value with infinite limit
assert_eq!((1.0 as $t).clamp_magnitude(inf), 1.0);
assert_eq!((-1.0 as $t).clamp_magnitude(inf), -1.0);

// MIN and MAX
let max = <$t>::MAX;
let min = <$t>::MIN;
// Large limit
let huge = 1e30;
assert_eq!(max.clamp_magnitude(huge), huge);
assert_eq!(min.clamp_magnitude(huge), -huge);
};
}

#[test]
fn test_clamp_magnitude_f32() {
check_float_clamp!(f32);
}

#[test]
fn test_clamp_magnitude_f64() {
check_float_clamp!(f64);
}

#[test]
#[should_panic(expected = "limit must be non-negative")]
fn test_clamp_magnitude_f32_panic_negative_limit() {
let _ = 1.0f32.clamp_magnitude(-1.0);
}

#[test]
#[should_panic(expected = "limit must be non-negative")]
fn test_clamp_magnitude_f64_panic_negative_limit() {
let _ = 1.0f64.clamp_magnitude(-1.0);
}

#[test]
#[should_panic]
fn test_clamp_magnitude_f32_panic_nan_limit() {
let _ = 1.0f32.clamp_magnitude(f32::NAN);
}

#[test]
#[should_panic]
fn test_clamp_magnitude_f64_panic_nan_limit() {
let _ = 1.0f64.clamp_magnitude(f64::NAN);
}
Loading