Implement clamp_magnitude for floats & signed integers
Added feature gate, documentation and tests also.
This commit is contained in:
parent
ceb7df7e6f
commit
ae7fa32e5b
7 changed files with 289 additions and 0 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
139
library/coretests/tests/num/clamp_magnitude.rs
Normal file
139
library/coretests/tests/num/clamp_magnitude.rs
Normal file
|
|
@ -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…
Add table
Add a link
Reference in a new issue