فهرست منبع

Merge #165 #171

165: Add saturating_mul() and refactor Saturating into subtraits. Fixes #40. r=cuviper a=trepetti

Hi all,

Taking the suggestion from #40, this pull request breaks out the saturating trait into three separate SaturatingAdd, SaturatingSub and SaturatingMul traits, borrowing the idea from Checked* and Wrapping*. In terms of native ops, SaturatingNeg would be an option on signed types once the saturating_neg() API is stable on signed integer primitives.

I know there is concern about breaking changes, so I was thinking that I could add a wrapping Saturating trait for backwards compatibility that retains the original functionality:

```
pub trait Saturating: SaturatingAdd + SaturatingSub {}
impl<T> Saturating for T where T: SaturatingAdd + SaturatingSub {}
```

This is not included in the current version, but I would be happy to add.

-Tom (trepetti@cs.columbia.edu)

171: Add FloatConst::{LOG10_2, LOG2_10} r=cuviper a=cuviper

These correspond to the `extra_log_consts` added in Rust 1.43.

Co-authored-by: Tom Repetti <trepetti@cs.columbia.edu>
Co-authored-by: Josh Stone <cuviper@gmail.com>
bors[bot] 4 سال پیش
والد
کامیت
9d54f39df9
3فایلهای تغییر یافته به همراه144 افزوده شده و 6 حذف شده
  1. 32 1
      src/float.rs
  2. 1 1
      src/lib.rs
  3. 111 4
      src/ops/saturating.rs

+ 32 - 1
src/float.rs

@@ -1,6 +1,6 @@
 use core::mem;
 use core::num::FpCategory;
-use core::ops::{Add, Neg};
+use core::ops::{Add, Div, Neg};
 
 use core::f32;
 use core::f64;
@@ -2252,6 +2252,16 @@ macro_rules! float_const_impl {
             fn TAU() -> Self where Self: Sized + Add<Self, Output = Self> {
                 Self::PI() + Self::PI()
             }
+            #[doc = "Return `log10(2.0)`."]
+            #[inline]
+            fn LOG10_2() -> Self where Self: Sized + Div<Self, Output = Self> {
+                Self::LN_2() / Self::LN_10()
+            }
+            #[doc = "Return `log2(10.0)`."]
+            #[inline]
+            fn LOG2_10() -> Self where Self: Sized + Div<Self, Output = Self> {
+                Self::LN_10() / Self::LN_2()
+            }
         }
         float_const_impl! { @float f32, $($constant,)+ }
         float_const_impl! { @float f64, $($constant,)+ }
@@ -2261,6 +2271,8 @@ macro_rules! float_const_impl {
             constant! {
                 $( $constant() -> $T::consts::$constant; )+
                 TAU() -> 6.28318530717958647692528676655900577;
+                LOG10_2() -> 0.301029995663981195213738894724493027;
+                LOG2_10() -> 3.32192809488736234787031942948939018;
             }
         }
     );
@@ -2356,4 +2368,23 @@ mod tests {
             57.2957795130823208767981548141051703
         );
     }
+
+    #[test]
+    #[cfg(any(feature = "std", feature = "libm"))]
+    fn extra_logs() {
+        use float::{Float, FloatConst};
+
+        fn check<F: Float + FloatConst>(diff: F) {
+            let _2 = F::from(2.0).unwrap();
+            assert!((F::LOG10_2() - F::log10(_2)).abs() < diff);
+            assert!((F::LOG10_2() - F::LN_2() / F::LN_10()).abs() < diff);
+
+            let _10 = F::from(10.0).unwrap();
+            assert!((F::LOG2_10() - F::log2(_10)).abs() < diff);
+            assert!((F::LOG2_10() - F::LN_10() / F::LN_2()).abs() < diff);
+        }
+
+        check::<f32>(1e-6);
+        check::<f64>(1e-12);
+    }
 }

+ 1 - 1
src/lib.rs

@@ -42,7 +42,7 @@ pub use ops::checked::{
 };
 pub use ops::inv::Inv;
 pub use ops::mul_add::{MulAdd, MulAddAssign};
-pub use ops::saturating::Saturating;
+pub use ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub};
 pub use ops::wrapping::{
     WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
 };

+ 111 - 4
src/ops/saturating.rs

@@ -1,4 +1,7 @@
-/// Saturating math operations
+use core::ops::{Add, Mul, Sub};
+
+/// Saturating math operations. Deprecated, use `SaturatingAdd`, `SaturatingSub` and
+/// `SaturatingMul` instead.
 pub trait Saturating {
     /// Saturating addition operator.
     /// Returns a+b, saturating at the numeric bounds instead of overflowing.
@@ -9,7 +12,7 @@ pub trait Saturating {
     fn saturating_sub(self, v: Self) -> Self;
 }
 
-macro_rules! saturating_impl {
+macro_rules! deprecated_saturating_impl {
     ($trait_name:ident for $($t:ty)*) => {$(
         impl $trait_name for $t {
             #[inline]
@@ -25,6 +28,110 @@ macro_rules! saturating_impl {
     )*}
 }
 
-saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
+deprecated_saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
+#[cfg(has_i128)]
+deprecated_saturating_impl!(Saturating for i128 u128);
+
+macro_rules! saturating_impl {
+    ($trait_name:ident, $method:ident, $t:ty) => {
+        impl $trait_name for $t {
+            #[inline]
+            fn $method(&self, v: &Self) -> Self {
+                <$t>::$method(*self, *v)
+            }
+        }
+    };
+}
+
+/// Performs addition that saturates at the numeric bounds instead of overflowing.
+pub trait SaturatingAdd: Sized + Add<Self, Output = Self> {
+    /// Saturating addition. Computes `self + other`, saturating at the relevant high or low boundary of
+    /// the type.
+    fn saturating_add(&self, v: &Self) -> Self;
+}
+
+saturating_impl!(SaturatingAdd, saturating_add, u8);
+saturating_impl!(SaturatingAdd, saturating_add, u16);
+saturating_impl!(SaturatingAdd, saturating_add, u32);
+saturating_impl!(SaturatingAdd, saturating_add, u64);
+saturating_impl!(SaturatingAdd, saturating_add, usize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingAdd, saturating_add, u128);
+
+saturating_impl!(SaturatingAdd, saturating_add, i8);
+saturating_impl!(SaturatingAdd, saturating_add, i16);
+saturating_impl!(SaturatingAdd, saturating_add, i32);
+saturating_impl!(SaturatingAdd, saturating_add, i64);
+saturating_impl!(SaturatingAdd, saturating_add, isize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingAdd, saturating_add, i128);
+
+/// Performs subtraction that saturates at the numeric bounds instead of overflowing.
+pub trait SaturatingSub: Sized + Sub<Self, Output = Self> {
+    /// Saturating subtraction. Computes `self - other`, saturating at the relevant high or low boundary of
+    /// the type.
+    fn saturating_sub(&self, v: &Self) -> Self;
+}
+
+saturating_impl!(SaturatingSub, saturating_sub, u8);
+saturating_impl!(SaturatingSub, saturating_sub, u16);
+saturating_impl!(SaturatingSub, saturating_sub, u32);
+saturating_impl!(SaturatingSub, saturating_sub, u64);
+saturating_impl!(SaturatingSub, saturating_sub, usize);
 #[cfg(has_i128)]
-saturating_impl!(Saturating for i128 u128);
+saturating_impl!(SaturatingSub, saturating_sub, u128);
+
+saturating_impl!(SaturatingSub, saturating_sub, i8);
+saturating_impl!(SaturatingSub, saturating_sub, i16);
+saturating_impl!(SaturatingSub, saturating_sub, i32);
+saturating_impl!(SaturatingSub, saturating_sub, i64);
+saturating_impl!(SaturatingSub, saturating_sub, isize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingSub, saturating_sub, i128);
+
+/// Performs multiplication that saturates at the numeric bounds instead of overflowing.
+pub trait SaturatingMul: Sized + Mul<Self, Output = Self> {
+    /// Saturating multiplication. Computes `self * other`, saturating at the relevant high or low boundary of
+    /// the type.
+    fn saturating_mul(&self, v: &Self) -> Self;
+}
+
+saturating_impl!(SaturatingMul, saturating_mul, u8);
+saturating_impl!(SaturatingMul, saturating_mul, u16);
+saturating_impl!(SaturatingMul, saturating_mul, u32);
+saturating_impl!(SaturatingMul, saturating_mul, u64);
+saturating_impl!(SaturatingMul, saturating_mul, usize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingMul, saturating_mul, u128);
+
+saturating_impl!(SaturatingMul, saturating_mul, i8);
+saturating_impl!(SaturatingMul, saturating_mul, i16);
+saturating_impl!(SaturatingMul, saturating_mul, i32);
+saturating_impl!(SaturatingMul, saturating_mul, i64);
+saturating_impl!(SaturatingMul, saturating_mul, isize);
+#[cfg(has_i128)]
+saturating_impl!(SaturatingMul, saturating_mul, i128);
+
+// TODO: add SaturatingNeg for signed integer primitives once the saturating_neg() API is stable.
+
+#[test]
+fn test_saturating_traits() {
+    fn saturating_add<T: SaturatingAdd>(a: T, b: T) -> T {
+        a.saturating_add(&b)
+    }
+    fn saturating_sub<T: SaturatingSub>(a: T, b: T) -> T {
+        a.saturating_sub(&b)
+    }
+    fn saturating_mul<T: SaturatingMul>(a: T, b: T) -> T {
+        a.saturating_mul(&b)
+    }
+    assert_eq!(saturating_add(255, 1), 255u8);
+    assert_eq!(saturating_add(127, 1), 127i8);
+    assert_eq!(saturating_add(-128, -1), -128i8);
+    assert_eq!(saturating_sub(0, 1), 0u8);
+    assert_eq!(saturating_sub(-128, 1), -128i8);
+    assert_eq!(saturating_sub(127, -1), 127i8);
+    assert_eq!(saturating_mul(255, 2), 255u8);
+    assert_eq!(saturating_mul(127, 2), 127i8);
+    assert_eq!(saturating_mul(-128, 2), -128i8);
+}