Skip to content

Commit

Permalink
Merge #165 #171
Browse files Browse the repository at this point in the history
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 ([email protected])

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 <[email protected]>
Co-authored-by: Josh Stone <[email protected]>
  • Loading branch information
3 people authored Jun 11, 2020
3 parents cf16338 + 5f00e22 + e9fcdb0 commit 9d54f39
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 6 deletions.
33 changes: 32 additions & 1 deletion src/float.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,)+ }
Expand All @@ -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;
}
}
);
Expand Down Expand Up @@ -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);
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down
115 changes: 111 additions & 4 deletions src/ops/saturating.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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]
Expand All @@ -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);
}

0 comments on commit 9d54f39

Please sign in to comment.