Implement `clamp_magnitude` for floats & signed integers

Added feature gate, documentation and tests also.
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index e710153..f51b561 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -1276,6 +1276,38 @@ pub const fn clamp(mut self, min: f128, max: f128) -> 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.
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index aa8342a..318c959 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -1254,6 +1254,38 @@ pub const fn clamp(mut self, min: f16, max: f16) -> 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.
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 3070e1d..91e276c 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1431,6 +1431,35 @@ pub const fn clamp(mut self, min: f32, max: f32) -> 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.
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index dc8ccc5..a4b2979 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1429,6 +1429,35 @@ pub const fn clamp(mut self, min: f64, max: f64) -> 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.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 7d395eb..9134d37 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -3855,5 +3855,32 @@ pub const fn min_value() -> Self {
         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
+            }
+        }
     }
 }
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 80b6203..124a8cf 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -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)]
diff --git a/library/coretests/tests/num/clamp_magnitude.rs b/library/coretests/tests/num/clamp_magnitude.rs
new file mode 100644
index 0000000..0f96e55
--- /dev/null
+++ b/library/coretests/tests/num/clamp_magnitude.rs
@@ -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);
+}