From 1ea0c354689e2a4730797294a25e032e9bbbbd3b Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 10:44:51 +0800 Subject: [PATCH 01/13] Add support for euclidean division and modulation --- src/lib.rs | 2 +- src/ops/euclid.rs | 227 ++++++++++++++++++++++++++++++++++++++++++++++ src/ops/mod.rs | 1 + 3 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/ops/euclid.rs diff --git a/src/lib.rs b/src/lib.rs index 85977d0c..2a561fac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ pub use ops::wrapping::{ }; pub use pow::{checked_pow, pow, Pow}; pub use sign::{abs, abs_sub, signum, Signed, Unsigned}; - +pub use ops::euclid::{DivRemEuclid,CheckedDivRemEuclid}; #[macro_use] mod macros; diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs new file mode 100644 index 00000000..e413337c --- /dev/null +++ b/src/ops/euclid.rs @@ -0,0 +1,227 @@ +use core::ops::{Div, Rem}; +use Float; + +pub trait DivRemEuclid: Sized + Div + Rem { + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::DivRemEuclid; + /// + /// let a: i32 = 7; + /// let b: i32 = 4; + /// assert_eq!(DivRemEuclid::div_euclid(&a,&b), 1); // 7 > 4 * 1 + /// assert_eq!(DivRemEuclid::div_euclid(&-a,&b), -2); // -7 >= 4 * -2 + /// assert_eq!(DivRemEuclid::div_euclid(&a,&-b), -1); // 7 >= -4 * -1 + /// assert_eq!(DivRemEuclid::div_euclid(&-a,&-b), 2); // -7 >= -4 * 2 + /// ``` + fn div_euclid(&self, v: &Self) -> Self; + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximatively. + /// + /// # Examples + /// + /// ``` + /// use num_traits::DivRemEuclid; + /// + /// let a: f32 = 7.0; + /// let b: f32 = 4.0; + /// assert_eq!(DivRemEuclid::rem_euclid(&a,&b), 3.0); + /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&b), 1.0); + /// assert_eq!(DivRemEuclid::rem_euclid(&a,&-b), 3.0); + /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&-b), 1.0); + /// ``` + fn rem_euclid(&self, v: &Self) -> Self; +} +macro_rules! div_rem_euclid_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn div_euclid(&self, v: &$t) -> Self { + <$t>::div_euclid(*self, *v) + } + + #[inline] + fn rem_euclid(&self, v: &$t) -> Self { + <$t>::rem_euclid(*self, *v) + } + + } + )*} +} +div_rem_euclid_impl!(DivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +#[cfg(has_i128)] +div_rem_euclid_impl!(DivRemEuclid for i128 u128); + +#[cfg(any(feature = "std", feature = "libm"))] +impl DivRemEuclid for f32 { + fn div_euclid(&self, rhs: &f32) -> f32 { + let q = ::trunc(self / rhs); + if self % rhs < 0.0 { + return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + fn rem_euclid(&self, rhs: &f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + ::abs(*rhs) + } else { + r + } + } +} + +#[cfg(any(feature = "std", feature = "libm"))] +impl DivRemEuclid for f64 { + fn div_euclid(&self, rhs: &f64) -> f64 { + let q = ::trunc(self / rhs); + if self % rhs < 0.0 { + return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + fn rem_euclid(&self, rhs: &f64) -> f64 { + let r = self % rhs; + if r < 0.0 { + r + ::abs(*rhs) + } else { + r + } + } +} + +pub trait CheckedDivRemEuclid: Sized + Div + Rem { + /// Performs euclid division that returns `None` instead of panicking on division by zero + /// and instead of wrapping around on underflow and overflow. + fn checked_div_euclid(&self, v: &Self) -> Option; + + /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and + /// division by zero. If any of that happens, `None` is returned. + fn checked_rem_euclid(&self, v: &Self) -> Option; +} + +macro_rules! checked_div_rem_euclid_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn checked_div_euclid(&self, v: &$t) -> Option<$t> { + <$t>::checked_div_euclid(*self, *v) + } + + #[inline] + fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { + <$t>::checked_rem_euclid(*self, *v) + } + } + )*} +} +checked_div_rem_euclid_impl!(CheckedDivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +#[cfg(has_i128)] +checked_div_rem_euclid_impl!(CheckedDivRemEuclid for i128 u128); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn euclid_unsigned() { + macro_rules! test_euclid { + ($($t:ident)+) => { + $( + { + let x: $t = 10; + let y: $t = 3; + assert_eq!(DivRemEuclid::div_euclid(&x,&y),3); + assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1); + } + )+ + }; + } + + test_euclid!(usize u8 u16 u32 u64 isize); + } + + #[test] + fn euclid_signed() { + macro_rules! test_euclid { + ($($t:ident)+) => { + $( + { + let x: $t = 10; + let y: $t = -3; + assert_eq!(DivRemEuclid::div_euclid(&x,&y),-3); + assert_eq!(DivRemEuclid::div_euclid(&-x,&y),4); + assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1); + assert_eq!(DivRemEuclid::rem_euclid(&-x,&y),2); + let x: $t = $t::MIN+1; + let y: $t = -1; + assert_eq!(DivRemEuclid::div_euclid(&x,&y),$t::MAX); + } + )+ + }; + } + + test_euclid!(i8 i16 i32 i64); + } + + #[test] + #[cfg(any(feature = "std", feature = "libm"))] + fn euclid_float() { + macro_rules! test_euclid { + ($($t:ident)+) => { + $( + { + let x: $t = 12.1; + let y: $t = 3.2; + assert!(DivRemEuclid::div_euclid(&x,&y)*y+DivRemEuclid::rem_euclid(&x,&y)-x + <=46.4 * $t::EPSILON); + assert!(DivRemEuclid::div_euclid(&x,&-y)*-y+DivRemEuclid::rem_euclid(&x,&-y)-x + <= 46.4 * $t::EPSILON); + assert!(DivRemEuclid::div_euclid(&-x,&y)*y+DivRemEuclid::rem_euclid(&-x,&y)-(-x) + <= 46.4 * $t::EPSILON); + assert!(DivRemEuclid::div_euclid(&-x,&-y)*-y+DivRemEuclid::rem_euclid(&-x,&-y)-(-x) + <= 46.4 * $t::EPSILON); + } + )+ + }; + } + + test_euclid!(f32 f64); + } + + #[test] + fn euclid_checked() { + macro_rules! test_euclid_checked { + ($($t:ident)+) => { + $( + { + assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&$t::MIN,&-1),None); + assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&$t::MIN,&-1),None); + assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&1,&0),None); + assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&1,&0),None); + } + )+ + }; + } + + test_euclid_checked!(i8 i16 i32 i64); + } +} diff --git a/src/ops/mod.rs b/src/ops/mod.rs index 73c4f902..ecbd487d 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -1,5 +1,6 @@ pub mod checked; pub mod inv; +pub mod euclid; pub mod mul_add; pub mod overflowing; pub mod saturating; From 87811d7f4b8a11ea93297615540f267105d8a2a7 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 10:58:31 +0800 Subject: [PATCH 02/13] fixes float::Float and fmt --- src/lib.rs | 2 +- src/ops/euclid.rs | 3 +-- src/ops/mod.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2a561fac..3fdc91f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,7 @@ pub use int::PrimInt; pub use ops::checked::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, }; +pub use ops::euclid::{CheckedDivRemEuclid, DivRemEuclid}; pub use ops::inv::Inv; pub use ops::mul_add::{MulAdd, MulAddAssign}; pub use ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub}; @@ -48,7 +49,6 @@ pub use ops::wrapping::{ }; pub use pow::{checked_pow, pow, Pow}; pub use sign::{abs, abs_sub, signum, Signed, Unsigned}; -pub use ops::euclid::{DivRemEuclid,CheckedDivRemEuclid}; #[macro_use] mod macros; diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index e413337c..eacaf8a9 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -1,6 +1,5 @@ use core::ops::{Div, Rem}; -use Float; - +use float::Float; pub trait DivRemEuclid: Sized + Div + Rem { /// Calculates Euclidean division, the matching method for `rem_euclid`. /// diff --git a/src/ops/mod.rs b/src/ops/mod.rs index ecbd487d..585879f6 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -1,6 +1,6 @@ pub mod checked; -pub mod inv; pub mod euclid; +pub mod inv; pub mod mul_add; pub mod overflowing; pub mod saturating; From 3672ce56e9c64e3b78bfacb99d5116377c3fcc9e Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 11:03:34 +0800 Subject: [PATCH 03/13] fixes ::Float --- src/ops/euclid.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index eacaf8a9..f7fee506 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -1,5 +1,4 @@ use core::ops::{Div, Rem}; -use float::Float; pub trait DivRemEuclid: Sized + Div + Rem { /// Calculates Euclidean division, the matching method for `rem_euclid`. /// @@ -70,7 +69,7 @@ div_rem_euclid_impl!(DivRemEuclid for i128 u128); #[cfg(any(feature = "std", feature = "libm"))] impl DivRemEuclid for f32 { fn div_euclid(&self, rhs: &f32) -> f32 { - let q = ::trunc(self / rhs); + let q = ::trunc(self / rhs); if self % rhs < 0.0 { return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 }; } @@ -80,7 +79,7 @@ impl DivRemEuclid for f32 { fn rem_euclid(&self, rhs: &f32) -> f32 { let r = self % rhs; if r < 0.0 { - r + ::abs(*rhs) + r + ::abs(*rhs) } else { r } @@ -90,7 +89,7 @@ impl DivRemEuclid for f32 { #[cfg(any(feature = "std", feature = "libm"))] impl DivRemEuclid for f64 { fn div_euclid(&self, rhs: &f64) -> f64 { - let q = ::trunc(self / rhs); + let q = ::trunc(self / rhs); if self % rhs < 0.0 { return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 }; } @@ -100,7 +99,7 @@ impl DivRemEuclid for f64 { fn rem_euclid(&self, rhs: &f64) -> f64 { let r = self % rhs; if r < 0.0 { - r + ::abs(*rhs) + r + ::abs(*rhs) } else { r } From e7c3bcb3db6916f8a6698c2bd73cec2b8f3e295f Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 11:24:21 +0800 Subject: [PATCH 04/13] fixes example --- src/ops/euclid.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index f7fee506..a8033b94 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -37,12 +37,12 @@ pub trait DivRemEuclid: Sized + Div + Rem Self; } @@ -187,6 +187,8 @@ mod tests { ($($t:ident)+) => { $( { + use core::$t; + let x: $t = 12.1; let y: $t = 3.2; assert!(DivRemEuclid::div_euclid(&x,&y)*y+DivRemEuclid::rem_euclid(&x,&y)-x From 4ad77d65fabe020be5979260e6695075a786886f Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 12:30:20 +0800 Subject: [PATCH 05/13] Fixes use core::float --- src/ops/euclid.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index a8033b94..7272d3aa 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -187,8 +187,6 @@ mod tests { ($($t:ident)+) => { $( { - use core::$t; - let x: $t = 12.1; let y: $t = 3.2; assert!(DivRemEuclid::div_euclid(&x,&y)*y+DivRemEuclid::rem_euclid(&x,&y)-x From 2d761d484eb38d8817af137c51cce703646b7633 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 12:47:55 +0800 Subject: [PATCH 06/13] fixes method impl --- src/ops/euclid.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index 7272d3aa..8198fa19 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -47,24 +47,24 @@ pub trait DivRemEuclid: Sized + Div + Rem Self; } macro_rules! div_rem_euclid_impl { - ($trait_name:ident for $($t:ty)*) => {$( + ($trait_name:ident,$method:ident,$method_2:ident for $($t:ty)*) => {$( impl $trait_name for $t { #[inline] - fn div_euclid(&self, v: &$t) -> Self { - <$t>::div_euclid(*self, *v) + fn $method(&self, v: &$t) -> Self { + <$t>::$method(*self, *v) } #[inline] - fn rem_euclid(&self, v: &$t) -> Self { - <$t>::rem_euclid(*self, *v) + fn $method_2(&self, v: &$t) -> Self { + <$t>::$method_2(*self, *v) } } )*} } -div_rem_euclid_impl!(DivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +div_rem_euclid_impl!(DivRemEuclid,div_euclid,rem_euclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); #[cfg(has_i128)] -div_rem_euclid_impl!(DivRemEuclid for i128 u128); +div_rem_euclid_impl!(DivRemEuclid,div_euclid,rem_euclid for i128 u128); #[cfg(any(feature = "std", feature = "libm"))] impl DivRemEuclid for f32 { @@ -117,23 +117,23 @@ pub trait CheckedDivRemEuclid: Sized + Div + Rem {$( + ($trait_name:ident,$method:ident,$method_2:ident for $($t:ty)*) => {$( impl $trait_name for $t { #[inline] - fn checked_div_euclid(&self, v: &$t) -> Option<$t> { - <$t>::checked_div_euclid(*self, *v) + fn $method(&self, v: &$t) -> Option<$t> { + <$t>::$method(*self, *v) } #[inline] - fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { - <$t>::checked_rem_euclid(*self, *v) + fn $method_2(&self, v: &$t) -> Option<$t> { + <$t>::$method_2(*self, *v) } } )*} } -checked_div_rem_euclid_impl!(CheckedDivRemEuclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +checked_div_rem_euclid_impl!(CheckedDivRemEuclid,checked_div_euclid,checked_rem_euclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); #[cfg(has_i128)] -checked_div_rem_euclid_impl!(CheckedDivRemEuclid for i128 u128); +checked_div_rem_euclid_impl!(CheckedDivRemEuclid,checked_div_euclid,checked_rem_euclid for i128 u128); #[cfg(test)] mod tests { From b29d99b8379f1957426b32880cf39fdcd77f2ded Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 15:12:51 +0800 Subject: [PATCH 07/13] Fixes methods --- src/lib.rs | 2 +- src/ops/euclid.rs | 252 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 175 insertions(+), 79 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3fdc91f5..639ec9ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,7 +40,7 @@ pub use int::PrimInt; pub use ops::checked::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, }; -pub use ops::euclid::{CheckedDivRemEuclid, DivRemEuclid}; +pub use ops::euclid::{CheckedDivEuclid, CheckedRemEuclid, DivEuclid, RemEuclid}; pub use ops::inv::Inv; pub use ops::mul_add::{MulAdd, MulAddAssign}; pub use ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub}; diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index 8198fa19..86fc79cb 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -1,85 +1,132 @@ use core::ops::{Div, Rem}; -pub trait DivRemEuclid: Sized + Div + Rem { +pub trait DivEuclid: Sized + Div { /// Calculates Euclidean division, the matching method for `rem_euclid`. /// /// This computes the integer `n` such that - /// `self = n * rhs + self.rem_euclid(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. + /// `self = n * v + self.rem_euclid(v)`. + /// In other words, the result is `self / v` rounded to the integer `n` + /// such that `self >= n * v`. /// /// # Examples /// /// ``` - /// use num_traits::DivRemEuclid; + /// use num_traits::DivEuclid; /// /// let a: i32 = 7; /// let b: i32 = 4; - /// assert_eq!(DivRemEuclid::div_euclid(&a,&b), 1); // 7 > 4 * 1 - /// assert_eq!(DivRemEuclid::div_euclid(&-a,&b), -2); // -7 >= 4 * -2 - /// assert_eq!(DivRemEuclid::div_euclid(&a,&-b), -1); // 7 >= -4 * -1 - /// assert_eq!(DivRemEuclid::div_euclid(&-a,&-b), 2); // -7 >= -4 * 2 + /// assert_eq!(DivEuclid::div_euclid(a,b), 1); // 7 > 4 * 1 + /// assert_eq!(DivEuclid::div_euclid(-a,b), -2); // -7 >= 4 * -2 + /// assert_eq!(DivEuclid::div_euclid(a,-b), -1); // 7 >= -4 * -1 + /// assert_eq!(DivEuclid::div_euclid(-a,-b), 2); // -7 >= -4 * 2 /// ``` - fn div_euclid(&self, v: &Self) -> Self; - - /// Calculates the least nonnegative remainder of `self (mod rhs)`. + fn div_euclid(self, v: Self) -> Self; +} +pub trait RemEuclid: Sized + Rem { + /// Calculates the least nonnegative remainder of `self (mod v)`. /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// In particular, the return value `r` satisfies `0.0 <= r < v.abs()` in /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// result in `r == v.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `v.abs()` in magnitude and `self < 0.0`. /// This result is not an element of the function's codomain, but it is the /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// property `self == self.div_euclid(v) * v + self.rem_euclid(v)` /// approximatively. /// /// # Examples /// /// ``` - /// use num_traits::DivRemEuclid; + /// use num_traits::RemEuclid; /// /// let a: i32 = 7; /// let b: i32 = 4; - /// assert_eq!(DivRemEuclid::rem_euclid(&a,&b), 3); - /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&b), 1); - /// assert_eq!(DivRemEuclid::rem_euclid(&a,&-b), 3); - /// assert_eq!(DivRemEuclid::rem_euclid(&-a,&-b), 1); + /// assert_eq!(RemEuclid::rem_euclid(a,b), 3); + /// assert_eq!(RemEuclid::rem_euclid(-a,b), 1); + /// assert_eq!(RemEuclid::rem_euclid(a,-b), 3); + /// assert_eq!(RemEuclid::rem_euclid(-a,-b), 1); /// ``` - fn rem_euclid(&self, v: &Self) -> Self; + fn rem_euclid(self, v: Self) -> Self; } -macro_rules! div_rem_euclid_impl { - ($trait_name:ident,$method:ident,$method_2:ident for $($t:ty)*) => {$( +macro_rules! div_euclid_int_impl { + ($trait_name:ident for $($t:ty)*) => {$( impl $trait_name for $t { #[inline] - fn $method(&self, v: &$t) -> Self { - <$t>::$method(*self, *v) + fn div_euclid(self, v: $t) -> Self { + let q = self / v; + if self % v < 0 { + return if v > 0 { q - 1 } else { q + 1 } + } + q } - + } + )*} +} +macro_rules! div_euclid_uint_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { #[inline] - fn $method_2(&self, v: &$t) -> Self { - <$t>::$method_2(*self, *v) + fn div_euclid(self, v: $t) -> Self { + self / v } - } )*} } -div_rem_euclid_impl!(DivRemEuclid,div_euclid,rem_euclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +macro_rules! rem_euclid_int_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn rem_euclid(self, v: $t) -> Self { + let r = self % v; + if r < 0 { + if v < 0 { + r - v + } else { + r + v + } + } else { + r + } + } + } + )*} +} +macro_rules! rem_euclid_uint_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn rem_euclid(self, v: $t) -> Self { + self % v + } + } + )*} +} +div_euclid_int_impl!(DivEuclid for i8 i16 i32 i64); +div_euclid_uint_impl!(DivEuclid for isize usize u8 u16 u32 u64); +rem_euclid_int_impl!(RemEuclid for i8 i16 i32 i64); +rem_euclid_uint_impl!(RemEuclid for isize usize u8 u16 u32 u64); #[cfg(has_i128)] -div_rem_euclid_impl!(DivRemEuclid,div_euclid,rem_euclid for i128 u128); +div_euclid_int_impl!(DivEuclid for i128); +div_euclid_uint_impl!(DivEuclid for u128); +rem_euclid_int_impl!(RemEuclid for i128); +rem_euclid_uint_impl!(RemEuclid for u128); #[cfg(any(feature = "std", feature = "libm"))] -impl DivRemEuclid for f32 { - fn div_euclid(&self, rhs: &f32) -> f32 { - let q = ::trunc(self / rhs); - if self % rhs < 0.0 { - return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 }; +impl DivEuclid for f32 { + fn div_euclid(self, v: f32) -> f32 { + let q = ::trunc(self / v); + if self % v < 0.0 { + return if v > 0.0 { q - 1.0 } else { q + 1.0 }; } q } +} - fn rem_euclid(&self, rhs: &f32) -> f32 { - let r = self % rhs; +#[cfg(any(feature = "std", feature = "libm"))] +impl RemEuclid for f32 { + fn rem_euclid(self, v: f32) -> f32 { + let r = self % v; if r < 0.0 { - r + ::abs(*rhs) + r + ::abs(v) } else { r } @@ -87,53 +134,102 @@ impl DivRemEuclid for f32 { } #[cfg(any(feature = "std", feature = "libm"))] -impl DivRemEuclid for f64 { - fn div_euclid(&self, rhs: &f64) -> f64 { - let q = ::trunc(self / rhs); - if self % rhs < 0.0 { - return if *rhs > 0.0 { q - 1.0 } else { q + 1.0 }; +impl DivEuclid for f64 { + fn div_euclid(self, v: f64) -> f64 { + let q = ::trunc(self / v); + if self % v < 0.0 { + return if v > 0.0 { q - 1.0 } else { q + 1.0 }; } q } - - fn rem_euclid(&self, rhs: &f64) -> f64 { - let r = self % rhs; +} +#[cfg(any(feature = "std", feature = "libm"))] +impl RemEuclid for f64 { + fn rem_euclid(self, v: f64) -> f64 { + let r = self % v; if r < 0.0 { - r + ::abs(*rhs) + r + ::abs(v) } else { r } } } -pub trait CheckedDivRemEuclid: Sized + Div + Rem { +pub trait CheckedDivEuclid: DivEuclid { /// Performs euclid division that returns `None` instead of panicking on division by zero /// and instead of wrapping around on underflow and overflow. - fn checked_div_euclid(&self, v: &Self) -> Option; - + fn checked_div_euclid(self, v: Self) -> Option; +} +pub trait CheckedRemEuclid: RemEuclid { /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and /// division by zero. If any of that happens, `None` is returned. - fn checked_rem_euclid(&self, v: &Self) -> Option; + fn checked_rem_euclid(self, v: Self) -> Option; } - -macro_rules! checked_div_rem_euclid_impl { - ($trait_name:ident,$method:ident,$method_2:ident for $($t:ty)*) => {$( +macro_rules! checked_div_euclid_int_impl { + ($trait_name:ident for $($t:ty)*) => {$( impl $trait_name for $t { #[inline] - fn $method(&self, v: &$t) -> Option<$t> { - <$t>::$method(*self, *v) + fn checked_div_euclid(self, v: $t) -> Option<$t> { + if v == 0 || (self == Self::MIN && v == -1) { + None + } else { + Some(DivEuclid::div_euclid(self,v)) + } } - + } + )*} +} +macro_rules! checked_div_euclid_uint_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn checked_div_euclid(self, v: $t) -> Option<$t> { + if v == 0{ + None + } else { + Some(DivEuclid::div_euclid(self,v)) + } + } + } + )*} +} +macro_rules! checked_rem_euclid_int_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn checked_rem_euclid(self, v: $t) -> Option<$t> { + if v == 0 || (self == Self::MIN && v == -1) { + None + } else { + Some(RemEuclid::rem_euclid(self,v)) + } + } + } + )*} +} +macro_rules! checked_rem_euclid_uint_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { #[inline] - fn $method_2(&self, v: &$t) -> Option<$t> { - <$t>::$method_2(*self, *v) + fn checked_rem_euclid(self, v: $t) -> Option<$t> { + if v == 0{ + None + } else { + Some(RemEuclid::rem_euclid(self,v)) + } } } )*} } -checked_div_rem_euclid_impl!(CheckedDivRemEuclid,checked_div_euclid,checked_rem_euclid for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +checked_div_euclid_int_impl!(CheckedDivEuclid for i8 i16 i32 i64); +checked_div_euclid_uint_impl!(CheckedDivEuclid for isize usize u8 u16 u32 u64); +checked_rem_euclid_int_impl!(CheckedRemEuclid for i8 i16 i32 i64); +checked_rem_euclid_uint_impl!(CheckedRemEuclid for isize usize u8 u16 u32 u64); #[cfg(has_i128)] -checked_div_rem_euclid_impl!(CheckedDivRemEuclid,checked_div_euclid,checked_rem_euclid for i128 u128); +checked_div_euclid_int_impl!(CheckedDivEuclid for i128); +checked_div_euclid_uint_impl!(CheckedDivEuclid for u128); +checked_rem_euclid_int_impl!(CheckedRemEuclid for i128); +checked_rem_euclid_uint_impl!(CheckedRemEuclid for u128); #[cfg(test)] mod tests { @@ -147,8 +243,8 @@ mod tests { { let x: $t = 10; let y: $t = 3; - assert_eq!(DivRemEuclid::div_euclid(&x,&y),3); - assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1); + assert_eq!(DivEuclid::div_euclid(x,y),3); + assert_eq!(RemEuclid::rem_euclid(x,y),1); } )+ }; @@ -165,13 +261,13 @@ mod tests { { let x: $t = 10; let y: $t = -3; - assert_eq!(DivRemEuclid::div_euclid(&x,&y),-3); - assert_eq!(DivRemEuclid::div_euclid(&-x,&y),4); - assert_eq!(DivRemEuclid::rem_euclid(&x,&y),1); - assert_eq!(DivRemEuclid::rem_euclid(&-x,&y),2); + assert_eq!(DivEuclid::div_euclid(x,y),-3); + assert_eq!(DivEuclid::div_euclid(-x,y),4); + assert_eq!(RemEuclid::rem_euclid(x,y),1); + assert_eq!(RemEuclid::rem_euclid(-x,y),2); let x: $t = $t::MIN+1; let y: $t = -1; - assert_eq!(DivRemEuclid::div_euclid(&x,&y),$t::MAX); + assert_eq!(DivEuclid::div_euclid(x,y),$t::MAX); } )+ }; @@ -189,13 +285,13 @@ mod tests { { let x: $t = 12.1; let y: $t = 3.2; - assert!(DivRemEuclid::div_euclid(&x,&y)*y+DivRemEuclid::rem_euclid(&x,&y)-x + assert!(DivEuclid::div_euclid(x,y)*y+RemEuclid::rem_euclid(x,y)-x <=46.4 * $t::EPSILON); - assert!(DivRemEuclid::div_euclid(&x,&-y)*-y+DivRemEuclid::rem_euclid(&x,&-y)-x + assert!(DivEuclid::div_euclid(x,-y)*-y+RemEuclid::rem_euclid(x,-y)-x <= 46.4 * $t::EPSILON); - assert!(DivRemEuclid::div_euclid(&-x,&y)*y+DivRemEuclid::rem_euclid(&-x,&y)-(-x) + assert!(DivEuclid::div_euclid(-x,y)*y+RemEuclid::rem_euclid(-x,y)-(-x) <= 46.4 * $t::EPSILON); - assert!(DivRemEuclid::div_euclid(&-x,&-y)*-y+DivRemEuclid::rem_euclid(&-x,&-y)-(-x) + assert!(DivEuclid::div_euclid(-x,-y)*-y+RemEuclid::rem_euclid(-x,-y)-(-x) <= 46.4 * $t::EPSILON); } )+ @@ -211,10 +307,10 @@ mod tests { ($($t:ident)+) => { $( { - assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&$t::MIN,&-1),None); - assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&$t::MIN,&-1),None); - assert_eq!(CheckedDivRemEuclid::checked_div_euclid(&1,&0),None); - assert_eq!(CheckedDivRemEuclid::checked_rem_euclid(&1,&0),None); + assert_eq!(CheckedDivEuclid::checked_div_euclid($t::MIN,-1),None); + assert_eq!(CheckedRemEuclid::checked_rem_euclid($t::MIN,-1),None); + assert_eq!(CheckedDivEuclid::checked_div_euclid(1,0),None); + assert_eq!(CheckedRemEuclid::checked_rem_euclid(1,0),None); } )+ }; From c49f5110ec2e1a0e9ba9018ee811b4df73d7413c Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 15:25:30 +0800 Subject: [PATCH 08/13] fixes MIN --- src/ops/euclid.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index 86fc79cb..c4ed890b 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -106,8 +106,11 @@ rem_euclid_int_impl!(RemEuclid for i8 i16 i32 i64); rem_euclid_uint_impl!(RemEuclid for isize usize u8 u16 u32 u64); #[cfg(has_i128)] div_euclid_int_impl!(DivEuclid for i128); +#[cfg(has_i128)] div_euclid_uint_impl!(DivEuclid for u128); +#[cfg(has_i128)] rem_euclid_int_impl!(RemEuclid for i128); +#[cfg(has_i128)] rem_euclid_uint_impl!(RemEuclid for u128); #[cfg(any(feature = "std", feature = "libm"))] @@ -170,7 +173,7 @@ macro_rules! checked_div_euclid_int_impl { impl $trait_name for $t { #[inline] fn checked_div_euclid(self, v: $t) -> Option<$t> { - if v == 0 || (self == Self::MIN && v == -1) { + if v == 0 || (self == Self::min_value() && v == -1) { None } else { Some(DivEuclid::div_euclid(self,v)) @@ -198,7 +201,7 @@ macro_rules! checked_rem_euclid_int_impl { impl $trait_name for $t { #[inline] fn checked_rem_euclid(self, v: $t) -> Option<$t> { - if v == 0 || (self == Self::MIN && v == -1) { + if v == 0 || (self == Self::min_value() && v == -1) { None } else { Some(RemEuclid::rem_euclid(self,v)) @@ -227,8 +230,11 @@ checked_rem_euclid_int_impl!(CheckedRemEuclid for i8 i16 i32 i64); checked_rem_euclid_uint_impl!(CheckedRemEuclid for isize usize u8 u16 u32 u64); #[cfg(has_i128)] checked_div_euclid_int_impl!(CheckedDivEuclid for i128); +#[cfg(has_i128)] checked_div_euclid_uint_impl!(CheckedDivEuclid for u128); +#[cfg(has_i128)] checked_rem_euclid_int_impl!(CheckedRemEuclid for i128); +#[cfg(has_i128)] checked_rem_euclid_uint_impl!(CheckedRemEuclid for u128); #[cfg(test)] @@ -265,7 +271,7 @@ mod tests { assert_eq!(DivEuclid::div_euclid(-x,y),4); assert_eq!(RemEuclid::rem_euclid(x,y),1); assert_eq!(RemEuclid::rem_euclid(-x,y),2); - let x: $t = $t::MIN+1; + let x: $t = $t::min_value()+1; let y: $t = -1; assert_eq!(DivEuclid::div_euclid(x,y),$t::MAX); } @@ -307,8 +313,8 @@ mod tests { ($($t:ident)+) => { $( { - assert_eq!(CheckedDivEuclid::checked_div_euclid($t::MIN,-1),None); - assert_eq!(CheckedRemEuclid::checked_rem_euclid($t::MIN,-1),None); + assert_eq!(CheckedDivEuclid::checked_div_euclid($t::min_value(),-1),None); + assert_eq!(CheckedRemEuclid::checked_rem_euclid($t::min_value(),-1),None); assert_eq!(CheckedDivEuclid::checked_div_euclid(1,0),None); assert_eq!(CheckedRemEuclid::checked_rem_euclid(1,0),None); } From ee53faf9f22ea5ce1d5eef9d3078c5d50742dafe Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 13 Nov 2020 15:40:37 +0800 Subject: [PATCH 09/13] Fixes epsilon --- src/ops/euclid.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index c4ed890b..fe35e1d4 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -273,7 +273,7 @@ mod tests { assert_eq!(RemEuclid::rem_euclid(-x,y),2); let x: $t = $t::min_value()+1; let y: $t = -1; - assert_eq!(DivEuclid::div_euclid(x,y),$t::MAX); + assert_eq!(DivEuclid::div_euclid(x,y),$t::max_value()); } )+ }; @@ -292,13 +292,13 @@ mod tests { let x: $t = 12.1; let y: $t = 3.2; assert!(DivEuclid::div_euclid(x,y)*y+RemEuclid::rem_euclid(x,y)-x - <=46.4 * $t::EPSILON); + <=46.4 * <$t as ::Float>::epsilon()); assert!(DivEuclid::div_euclid(x,-y)*-y+RemEuclid::rem_euclid(x,-y)-x - <= 46.4 * $t::EPSILON); + <= 46.4 * <$t as ::Float>::epsilon()); assert!(DivEuclid::div_euclid(-x,y)*y+RemEuclid::rem_euclid(-x,y)-(-x) - <= 46.4 * $t::EPSILON); + <= 46.4 * <$t as ::Float>::epsilon()); assert!(DivEuclid::div_euclid(-x,-y)*-y+RemEuclid::rem_euclid(-x,-y)-(-x) - <= 46.4 * $t::EPSILON); + <= 46.4 * <$t as ::Float>::epsilon()); } )+ }; From 50afb16590ba59cdc3e047d21e1fc91faa487872 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Mon, 16 Nov 2020 16:50:14 +0800 Subject: [PATCH 10/13] fixes codes structure etc. --- src/lib.rs | 4 +- src/ops/euclid.rs | 199 +++++++++++++++++++--------------------------- 2 files changed, 84 insertions(+), 119 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 639ec9ed..6436421c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ pub use bounds::Bounded; #[cfg(any(feature = "std", feature = "libm"))] pub use float::Float; pub use float::FloatConst; +pub use float::FloatCore; // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; pub use identities::{one, zero, One, Zero}; @@ -40,7 +41,7 @@ pub use int::PrimInt; pub use ops::checked::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, }; -pub use ops::euclid::{CheckedDivEuclid, CheckedRemEuclid, DivEuclid, RemEuclid}; +pub use ops::euclid::{CheckedEuclid, Euclid}; pub use ops::inv::Inv; pub use ops::mul_add::{MulAdd, MulAddAssign}; pub use ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub}; @@ -49,6 +50,7 @@ pub use ops::wrapping::{ }; pub use pow::{checked_pow, pow, Pow}; pub use sign::{abs, abs_sub, signum, Signed, Unsigned}; + #[macro_use] mod macros; diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index fe35e1d4..b4ab6faf 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -1,5 +1,6 @@ use core::ops::{Div, Rem}; -pub trait DivEuclid: Sized + Div { + +pub trait Euclid: Sized + Div + Rem { /// Calculates Euclidean division, the matching method for `rem_euclid`. /// /// This computes the integer `n` such that @@ -10,18 +11,17 @@ pub trait DivEuclid: Sized + Div { /// # Examples /// /// ``` - /// use num_traits::DivEuclid; + /// use num_traits::Euclid; /// /// let a: i32 = 7; /// let b: i32 = 4; - /// assert_eq!(DivEuclid::div_euclid(a,b), 1); // 7 > 4 * 1 - /// assert_eq!(DivEuclid::div_euclid(-a,b), -2); // -7 >= 4 * -2 - /// assert_eq!(DivEuclid::div_euclid(a,-b), -1); // 7 >= -4 * -1 - /// assert_eq!(DivEuclid::div_euclid(-a,-b), 2); // -7 >= -4 * 2 + /// assert_eq!(Euclid::div_euclid(a, b), 1); // 7 > 4 * 1 + /// assert_eq!(Euclid::div_euclid(-a, b), -2); // -7 >= 4 * -2 + /// assert_eq!(Euclid::div_euclid(a, -b), -1); // 7 >= -4 * -1 + /// assert_eq!(Euclid::div_euclid(-a, -b), 2); // -7 >= -4 * 2 /// ``` fn div_euclid(self, v: Self) -> Self; -} -pub trait RemEuclid: Sized + Rem { + /// Calculates the least nonnegative remainder of `self (mod v)`. /// /// In particular, the return value `r` satisfies `0.0 <= r < v.abs()` in @@ -36,20 +36,20 @@ pub trait RemEuclid: Sized + Rem { /// # Examples /// /// ``` - /// use num_traits::RemEuclid; + /// use num_traits::Euclid; /// /// let a: i32 = 7; /// let b: i32 = 4; - /// assert_eq!(RemEuclid::rem_euclid(a,b), 3); - /// assert_eq!(RemEuclid::rem_euclid(-a,b), 1); - /// assert_eq!(RemEuclid::rem_euclid(a,-b), 3); - /// assert_eq!(RemEuclid::rem_euclid(-a,-b), 1); + /// assert_eq!(Euclid::rem_euclid(a, b), 3); + /// assert_eq!(Euclid::rem_euclid(-a, b), 1); + /// assert_eq!(Euclid::rem_euclid(a, -b), 3); + /// assert_eq!(Euclid::rem_euclid(-a, -b), 1); /// ``` fn rem_euclid(self, v: Self) -> Self; } -macro_rules! div_euclid_int_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { +macro_rules! euclid_int_impl { + ($($t:ty)*) => {$( + impl Euclid for $t { #[inline] fn div_euclid(self, v: $t) -> Self { let q = self / v; @@ -58,22 +58,7 @@ macro_rules! div_euclid_int_impl { } q } - } - )*} -} -macro_rules! div_euclid_uint_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { - #[inline] - fn div_euclid(self, v: $t) -> Self { - self / v - } - } - )*} -} -macro_rules! rem_euclid_int_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { + #[inline] fn rem_euclid(self, v: $t) -> Self { let r = self % v; @@ -90,9 +75,14 @@ macro_rules! rem_euclid_int_impl { } )*} } -macro_rules! rem_euclid_uint_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { +macro_rules! euclid_uint_impl { + ($($t:ty)*) => {$( + impl Euclid for $t { + #[inline] + fn div_euclid(self, v: $t) -> Self { + self / v + } + #[inline] fn rem_euclid(self, v: $t) -> Self { self % v @@ -100,142 +90,116 @@ macro_rules! rem_euclid_uint_impl { } )*} } -div_euclid_int_impl!(DivEuclid for i8 i16 i32 i64); -div_euclid_uint_impl!(DivEuclid for isize usize u8 u16 u32 u64); -rem_euclid_int_impl!(RemEuclid for i8 i16 i32 i64); -rem_euclid_uint_impl!(RemEuclid for isize usize u8 u16 u32 u64); -#[cfg(has_i128)] -div_euclid_int_impl!(DivEuclid for i128); +euclid_int_impl!(isize i8 i16 i32 i64); +euclid_uint_impl!(usize u8 u16 u32 u64); #[cfg(has_i128)] -div_euclid_uint_impl!(DivEuclid for u128); +euclid_int_impl!(i128); #[cfg(has_i128)] -rem_euclid_int_impl!(RemEuclid for i128); -#[cfg(has_i128)] -rem_euclid_uint_impl!(RemEuclid for u128); +euclid_uint_impl!(u128); -#[cfg(any(feature = "std", feature = "libm"))] -impl DivEuclid for f32 { +impl Euclid for f32 { + #[inline] fn div_euclid(self, v: f32) -> f32 { - let q = ::trunc(self / v); + let q = ::trunc(self / v); if self % v < 0.0 { return if v > 0.0 { q - 1.0 } else { q + 1.0 }; } q } -} -#[cfg(any(feature = "std", feature = "libm"))] -impl RemEuclid for f32 { + #[inline] fn rem_euclid(self, v: f32) -> f32 { let r = self % v; if r < 0.0 { - r + ::abs(v) + r + ::abs(v) } else { r } } } -#[cfg(any(feature = "std", feature = "libm"))] -impl DivEuclid for f64 { +impl Euclid for f64 { + #[inline] fn div_euclid(self, v: f64) -> f64 { - let q = ::trunc(self / v); + let q = ::trunc(self / v); if self % v < 0.0 { return if v > 0.0 { q - 1.0 } else { q + 1.0 }; } q } -} -#[cfg(any(feature = "std", feature = "libm"))] -impl RemEuclid for f64 { + + #[inline] fn rem_euclid(self, v: f64) -> f64 { let r = self % v; if r < 0.0 { - r + ::abs(v) + r + ::abs(v) } else { r } } } -pub trait CheckedDivEuclid: DivEuclid { +pub trait CheckedEuclid: Euclid { /// Performs euclid division that returns `None` instead of panicking on division by zero /// and instead of wrapping around on underflow and overflow. fn checked_div_euclid(self, v: Self) -> Option; -} -pub trait CheckedRemEuclid: RemEuclid { + /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and /// division by zero. If any of that happens, `None` is returned. fn checked_rem_euclid(self, v: Self) -> Option; } -macro_rules! checked_div_euclid_int_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { +macro_rules! checked_euclid_int_impl { + ($($t:ty)*) => {$( + impl CheckedEuclid for $t { #[inline] fn checked_div_euclid(self, v: $t) -> Option<$t> { if v == 0 || (self == Self::min_value() && v == -1) { None } else { - Some(DivEuclid::div_euclid(self,v)) + Some(Euclid::div_euclid(self, v)) } } - } - )*} -} -macro_rules! checked_div_euclid_uint_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { + #[inline] - fn checked_div_euclid(self, v: $t) -> Option<$t> { - if v == 0{ + fn checked_rem_euclid(self, v: $t) -> Option<$t> { + if v == 0 || (self == Self::min_value() && v == -1) { None } else { - Some(DivEuclid::div_euclid(self,v)) + Some(Euclid::rem_euclid(self, v)) } } } )*} } -macro_rules! checked_rem_euclid_int_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { +macro_rules! checked_euclid_uint_impl { + ($($t:ty)*) => {$( + impl CheckedEuclid for $t { #[inline] - fn checked_rem_euclid(self, v: $t) -> Option<$t> { - if v == 0 || (self == Self::min_value() && v == -1) { + fn checked_div_euclid(self, v: $t) -> Option<$t> { + if v == 0{ None } else { - Some(RemEuclid::rem_euclid(self,v)) + Some(Euclid::div_euclid(self, v)) } } - } - )*} -} -macro_rules! checked_rem_euclid_uint_impl { - ($trait_name:ident for $($t:ty)*) => {$( - impl $trait_name for $t { + #[inline] fn checked_rem_euclid(self, v: $t) -> Option<$t> { if v == 0{ None } else { - Some(RemEuclid::rem_euclid(self,v)) + Some(Euclid::rem_euclid(self, v)) } } } )*} } -checked_div_euclid_int_impl!(CheckedDivEuclid for i8 i16 i32 i64); -checked_div_euclid_uint_impl!(CheckedDivEuclid for isize usize u8 u16 u32 u64); -checked_rem_euclid_int_impl!(CheckedRemEuclid for i8 i16 i32 i64); -checked_rem_euclid_uint_impl!(CheckedRemEuclid for isize usize u8 u16 u32 u64); -#[cfg(has_i128)] -checked_div_euclid_int_impl!(CheckedDivEuclid for i128); -#[cfg(has_i128)] -checked_div_euclid_uint_impl!(CheckedDivEuclid for u128); +checked_euclid_int_impl!(isize i8 i16 i32 i64); +checked_euclid_uint_impl!(usize u8 u16 u32 u64); #[cfg(has_i128)] -checked_rem_euclid_int_impl!(CheckedRemEuclid for i128); +checked_euclid_int_impl!(i128); #[cfg(has_i128)] -checked_rem_euclid_uint_impl!(CheckedRemEuclid for u128); +checked_euclid_uint_impl!(u128); #[cfg(test)] mod tests { @@ -249,8 +213,8 @@ mod tests { { let x: $t = 10; let y: $t = 3; - assert_eq!(DivEuclid::div_euclid(x,y),3); - assert_eq!(RemEuclid::rem_euclid(x,y),1); + assert_eq!(Euclid::div_euclid(x, y),3); + assert_eq!(Euclid::rem_euclid(x, y),1); } )+ }; @@ -267,13 +231,13 @@ mod tests { { let x: $t = 10; let y: $t = -3; - assert_eq!(DivEuclid::div_euclid(x,y),-3); - assert_eq!(DivEuclid::div_euclid(-x,y),4); - assert_eq!(RemEuclid::rem_euclid(x,y),1); - assert_eq!(RemEuclid::rem_euclid(-x,y),2); + assert_eq!(Euclid::div_euclid(x, y),-3); + assert_eq!(Euclid::div_euclid(-x, y),4); + assert_eq!(Euclid::rem_euclid(x, y),1); + assert_eq!(Euclid::rem_euclid(-x, y),2); let x: $t = $t::min_value()+1; let y: $t = -1; - assert_eq!(DivEuclid::div_euclid(x,y),$t::max_value()); + assert_eq!(Euclid::div_euclid(x, y),$t::max_value()); } )+ }; @@ -283,7 +247,6 @@ mod tests { } #[test] - #[cfg(any(feature = "std", feature = "libm"))] fn euclid_float() { macro_rules! test_euclid { ($($t:ident)+) => { @@ -291,14 +254,14 @@ mod tests { { let x: $t = 12.1; let y: $t = 3.2; - assert!(DivEuclid::div_euclid(x,y)*y+RemEuclid::rem_euclid(x,y)-x - <=46.4 * <$t as ::Float>::epsilon()); - assert!(DivEuclid::div_euclid(x,-y)*-y+RemEuclid::rem_euclid(x,-y)-x - <= 46.4 * <$t as ::Float>::epsilon()); - assert!(DivEuclid::div_euclid(-x,y)*y+RemEuclid::rem_euclid(-x,y)-(-x) - <= 46.4 * <$t as ::Float>::epsilon()); - assert!(DivEuclid::div_euclid(-x,-y)*-y+RemEuclid::rem_euclid(-x,-y)-(-x) - <= 46.4 * <$t as ::Float>::epsilon()); + assert!(Euclid::div_euclid(x, y)*y+Euclid::rem_euclid(x, y)-x + <=46.4 * <$t as ::FloatCore>::epsilon()); + assert!(Euclid::div_euclid(x, -y)*-y+Euclid::rem_euclid(x, -y)-x + <= 46.4 * <$t as ::FloatCore>::epsilon()); + assert!(Euclid::div_euclid(-x, y)*y+Euclid::rem_euclid(-x, y)-(-x) + <= 46.4 * <$t as ::FloatCore>::epsilon()); + assert!(Euclid::div_euclid(-x, -y)*-y+Euclid::rem_euclid(-x, -y)-(-x) + <= 46.4 * <$t as ::FloatCore>::epsilon()); } )+ }; @@ -313,10 +276,10 @@ mod tests { ($($t:ident)+) => { $( { - assert_eq!(CheckedDivEuclid::checked_div_euclid($t::min_value(),-1),None); - assert_eq!(CheckedRemEuclid::checked_rem_euclid($t::min_value(),-1),None); - assert_eq!(CheckedDivEuclid::checked_div_euclid(1,0),None); - assert_eq!(CheckedRemEuclid::checked_rem_euclid(1,0),None); + assert_eq!(CheckedEuclid::checked_div_euclid($t::min_value(), -1),None); + assert_eq!(CheckedEuclid::checked_rem_euclid($t::min_value(), -1),None); + assert_eq!(CheckedEuclid::checked_div_euclid(1, 0),None); + assert_eq!(CheckedEuclid::checked_rem_euclid(1, 0),None); } )+ }; From 9c5034c7bbe40f648bfac848853bfc6b3e70871e Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Tue, 2 Mar 2021 10:33:29 +0800 Subject: [PATCH 11/13] take references as parameters --- src/lib.rs | 1 - src/ops/euclid.rs | 118 ++++++++++++++++++++++++---------------------- 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6436421c..bed87f36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,6 @@ pub use bounds::Bounded; #[cfg(any(feature = "std", feature = "libm"))] pub use float::Float; pub use float::FloatConst; -pub use float::FloatCore; // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; pub use identities::{one, zero, One, Zero}; diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index b4ab6faf..10231174 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -15,12 +15,12 @@ pub trait Euclid: Sized + Div + Rem { /// /// let a: i32 = 7; /// let b: i32 = 4; - /// assert_eq!(Euclid::div_euclid(a, b), 1); // 7 > 4 * 1 - /// assert_eq!(Euclid::div_euclid(-a, b), -2); // -7 >= 4 * -2 - /// assert_eq!(Euclid::div_euclid(a, -b), -1); // 7 >= -4 * -1 - /// assert_eq!(Euclid::div_euclid(-a, -b), 2); // -7 >= -4 * 2 + /// assert_eq!(Euclid::div_euclid(&a, &b), 1); // 7 > 4 * 1 + /// assert_eq!(Euclid::div_euclid(&-a, &b), -2); // -7 >= 4 * -2 + /// assert_eq!(Euclid::div_euclid(&a, &-b), -1); // 7 >= -4 * -1 + /// assert_eq!(Euclid::div_euclid(&-a, &-b), 2); // -7 >= -4 * 2 /// ``` - fn div_euclid(self, v: Self) -> Self; + fn div_euclid(&self, v: &Self) -> Self; /// Calculates the least nonnegative remainder of `self (mod v)`. /// @@ -40,30 +40,31 @@ pub trait Euclid: Sized + Div + Rem { /// /// let a: i32 = 7; /// let b: i32 = 4; - /// assert_eq!(Euclid::rem_euclid(a, b), 3); - /// assert_eq!(Euclid::rem_euclid(-a, b), 1); - /// assert_eq!(Euclid::rem_euclid(a, -b), 3); - /// assert_eq!(Euclid::rem_euclid(-a, -b), 1); + /// assert_eq!(Euclid::rem_euclid(&a, &b), 3); + /// assert_eq!(Euclid::rem_euclid(&-a, &b), 1); + /// assert_eq!(Euclid::rem_euclid(&a, &-b), 3); + /// assert_eq!(Euclid::rem_euclid(&-a, &-b), 1); /// ``` - fn rem_euclid(self, v: Self) -> Self; + fn rem_euclid(&self, v: &Self) -> Self; } + macro_rules! euclid_int_impl { ($($t:ty)*) => {$( impl Euclid for $t { #[inline] - fn div_euclid(self, v: $t) -> Self { + fn div_euclid(&self, v: &$t) -> Self { let q = self / v; if self % v < 0 { - return if v > 0 { q - 1 } else { q + 1 } + return if *v > 0 { q - 1 } else { q + 1 } } q } #[inline] - fn rem_euclid(self, v: $t) -> Self { + fn rem_euclid(&self, v: &$t) -> Self { let r = self % v; if r < 0 { - if v < 0 { + if *v < 0 { r - v } else { r + v @@ -75,21 +76,23 @@ macro_rules! euclid_int_impl { } )*} } + macro_rules! euclid_uint_impl { ($($t:ty)*) => {$( impl Euclid for $t { #[inline] - fn div_euclid(self, v: $t) -> Self { + fn div_euclid(&self, v: &$t) -> Self { self / v } #[inline] - fn rem_euclid(self, v: $t) -> Self { + fn rem_euclid(&self, v: &$t) -> Self { self % v } } )*} } + euclid_int_impl!(isize i8 i16 i32 i64); euclid_uint_impl!(usize u8 u16 u32 u64); #[cfg(has_i128)] @@ -99,19 +102,19 @@ euclid_uint_impl!(u128); impl Euclid for f32 { #[inline] - fn div_euclid(self, v: f32) -> f32 { - let q = ::trunc(self / v); + fn div_euclid(&self, v: &f32) -> f32 { + let q = ::trunc(self / v); if self % v < 0.0 { - return if v > 0.0 { q - 1.0 } else { q + 1.0 }; + return if *v > 0.0 { q - 1.0 } else { q + 1.0 }; } q } #[inline] - fn rem_euclid(self, v: f32) -> f32 { + fn rem_euclid(&self, v: &f32) -> f32 { let r = self % v; if r < 0.0 { - r + ::abs(v) + r + ::abs(*v) } else { r } @@ -120,19 +123,19 @@ impl Euclid for f32 { impl Euclid for f64 { #[inline] - fn div_euclid(self, v: f64) -> f64 { - let q = ::trunc(self / v); + fn div_euclid(&self, v: &f64) -> f64 { + let q = ::trunc(self / v); if self % v < 0.0 { - return if v > 0.0 { q - 1.0 } else { q + 1.0 }; + return if *v > 0.0 { q - 1.0 } else { q + 1.0 }; } q } #[inline] - fn rem_euclid(self, v: f64) -> f64 { + fn rem_euclid(&self, v: &f64) -> f64 { let r = self % v; if r < 0.0 { - r + ::abs(v) + r + ::abs(*v) } else { r } @@ -142,18 +145,19 @@ impl Euclid for f64 { pub trait CheckedEuclid: Euclid { /// Performs euclid division that returns `None` instead of panicking on division by zero /// and instead of wrapping around on underflow and overflow. - fn checked_div_euclid(self, v: Self) -> Option; + fn checked_div_euclid(&self, v: &Self) -> Option; /// Finds the euclid remainder of dividing two numbers, checking for underflow, overflow and /// division by zero. If any of that happens, `None` is returned. - fn checked_rem_euclid(self, v: Self) -> Option; + fn checked_rem_euclid(&self, v: &Self) -> Option; } + macro_rules! checked_euclid_int_impl { ($($t:ty)*) => {$( impl CheckedEuclid for $t { #[inline] - fn checked_div_euclid(self, v: $t) -> Option<$t> { - if v == 0 || (self == Self::min_value() && v == -1) { + fn checked_div_euclid(&self, v: &$t) -> Option<$t> { + if *v == 0 || (*self == Self::min_value() && *v == -1) { None } else { Some(Euclid::div_euclid(self, v)) @@ -161,8 +165,8 @@ macro_rules! checked_euclid_int_impl { } #[inline] - fn checked_rem_euclid(self, v: $t) -> Option<$t> { - if v == 0 || (self == Self::min_value() && v == -1) { + fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { + if *v == 0 || (*self == Self::min_value() && *v == -1) { None } else { Some(Euclid::rem_euclid(self, v)) @@ -171,12 +175,13 @@ macro_rules! checked_euclid_int_impl { } )*} } + macro_rules! checked_euclid_uint_impl { ($($t:ty)*) => {$( impl CheckedEuclid for $t { #[inline] - fn checked_div_euclid(self, v: $t) -> Option<$t> { - if v == 0{ + fn checked_div_euclid(&self, v: &$t) -> Option<$t> { + if *v == 0 { None } else { Some(Euclid::div_euclid(self, v)) @@ -184,8 +189,8 @@ macro_rules! checked_euclid_uint_impl { } #[inline] - fn checked_rem_euclid(self, v: $t) -> Option<$t> { - if v == 0{ + fn checked_rem_euclid(&self, v: &$t) -> Option<$t> { + if *v == 0 { None } else { Some(Euclid::rem_euclid(self, v)) @@ -194,6 +199,7 @@ macro_rules! checked_euclid_uint_impl { } )*} } + checked_euclid_int_impl!(isize i8 i16 i32 i64); checked_euclid_uint_impl!(usize u8 u16 u32 u64); #[cfg(has_i128)] @@ -213,8 +219,8 @@ mod tests { { let x: $t = 10; let y: $t = 3; - assert_eq!(Euclid::div_euclid(x, y),3); - assert_eq!(Euclid::rem_euclid(x, y),1); + assert_eq!(Euclid::div_euclid(&x, &y), 3); + assert_eq!(Euclid::rem_euclid(&x, &y), 1); } )+ }; @@ -231,13 +237,13 @@ mod tests { { let x: $t = 10; let y: $t = -3; - assert_eq!(Euclid::div_euclid(x, y),-3); - assert_eq!(Euclid::div_euclid(-x, y),4); - assert_eq!(Euclid::rem_euclid(x, y),1); - assert_eq!(Euclid::rem_euclid(-x, y),2); - let x: $t = $t::min_value()+1; + assert_eq!(Euclid::div_euclid(&x, &y), -3); + assert_eq!(Euclid::div_euclid(&-x, &y), 4); + assert_eq!(Euclid::rem_euclid(&x, &y), 1); + assert_eq!(Euclid::rem_euclid(&-x, &y), 2); + let x: $t = $t::min_value() + 1; let y: $t = -1; - assert_eq!(Euclid::div_euclid(x, y),$t::max_value()); + assert_eq!(Euclid::div_euclid(&x, &y), $t::max_value()); } )+ }; @@ -254,14 +260,14 @@ mod tests { { let x: $t = 12.1; let y: $t = 3.2; - assert!(Euclid::div_euclid(x, y)*y+Euclid::rem_euclid(x, y)-x - <=46.4 * <$t as ::FloatCore>::epsilon()); - assert!(Euclid::div_euclid(x, -y)*-y+Euclid::rem_euclid(x, -y)-x - <= 46.4 * <$t as ::FloatCore>::epsilon()); - assert!(Euclid::div_euclid(-x, y)*y+Euclid::rem_euclid(-x, y)-(-x) - <= 46.4 * <$t as ::FloatCore>::epsilon()); - assert!(Euclid::div_euclid(-x, -y)*-y+Euclid::rem_euclid(-x, -y)-(-x) - <= 46.4 * <$t as ::FloatCore>::epsilon()); + assert!(Euclid::div_euclid(&x, &y) * y + Euclid::rem_euclid(&x, &y) - x + <=46.4 * <$t as ::float::FloatCore>::epsilon()); + assert!(Euclid::div_euclid(&x, &-y) * -y + Euclid::rem_euclid(&x, &-y) - x + <= 46.4 * <$t as ::float::FloatCore>::epsilon()); + assert!(Euclid::div_euclid(&-x, &y) * y + Euclid::rem_euclid(&-x, &y) + x + <= 46.4 * <$t as ::float::FloatCore>::epsilon()); + assert!(Euclid::div_euclid(&-x, &-y) * -y + Euclid::rem_euclid(&-x, &-y) + x + <= 46.4 * <$t as ::float::FloatCore>::epsilon()); } )+ }; @@ -276,10 +282,10 @@ mod tests { ($($t:ident)+) => { $( { - assert_eq!(CheckedEuclid::checked_div_euclid($t::min_value(), -1),None); - assert_eq!(CheckedEuclid::checked_rem_euclid($t::min_value(), -1),None); - assert_eq!(CheckedEuclid::checked_div_euclid(1, 0),None); - assert_eq!(CheckedEuclid::checked_rem_euclid(1, 0),None); + assert_eq!(CheckedEuclid::checked_div_euclid(&$t::min_value(), &-1), None); + assert_eq!(CheckedEuclid::checked_rem_euclid(&$t::min_value(), &-1), None); + assert_eq!(CheckedEuclid::checked_div_euclid(&1, &0), None); + assert_eq!(CheckedEuclid::checked_rem_euclid(&1, &0), None); } )+ }; From 7861645c18d71f8dff72b1847643ff5de7ab86eb Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 29 Apr 2022 17:09:35 -0700 Subject: [PATCH 12/13] tweak euclid tests --- src/ops/euclid.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index 10231174..ef6546c1 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -226,7 +226,7 @@ mod tests { }; } - test_euclid!(usize u8 u16 u32 u64 isize); + test_euclid!(usize u8 u16 u32 u64); } #[test] @@ -249,7 +249,7 @@ mod tests { }; } - test_euclid!(i8 i16 i32 i64); + test_euclid!(isize i8 i16 i32 i64); } #[test] @@ -261,7 +261,7 @@ mod tests { let x: $t = 12.1; let y: $t = 3.2; assert!(Euclid::div_euclid(&x, &y) * y + Euclid::rem_euclid(&x, &y) - x - <=46.4 * <$t as ::float::FloatCore>::epsilon()); + <= 46.4 * <$t as ::float::FloatCore>::epsilon()); assert!(Euclid::div_euclid(&x, &-y) * -y + Euclid::rem_euclid(&x, &-y) - x <= 46.4 * <$t as ::float::FloatCore>::epsilon()); assert!(Euclid::div_euclid(&-x, &y) * y + Euclid::rem_euclid(&-x, &y) + x @@ -291,6 +291,6 @@ mod tests { }; } - test_euclid_checked!(i8 i16 i32 i64); + test_euclid_checked!(isize i8 i16 i32 i64); } } From 18575c287cd5053875f7a86dd7c38d3b5ad64efd Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 29 Apr 2022 17:53:50 -0700 Subject: [PATCH 13/13] Forward euclid methods when possible --- build.rs | 1 + src/ops/euclid.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/build.rs b/build.rs index 83c8eee0..887021d9 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,7 @@ fn main() { ac.emit_expression_cfg("1u32.reverse_bits()", "has_reverse_bits"); ac.emit_expression_cfg("1u32.trailing_ones()", "has_leading_trailing_ones"); ac.emit_expression_cfg("{ let mut x = 1; x += &2; }", "has_int_assignop_ref"); + ac.emit_expression_cfg("1u32.div_euclid(1u32)", "has_div_euclid"); autocfg::rerun_path("build.rs"); } diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs index ef6546c1..99b51279 100644 --- a/src/ops/euclid.rs +++ b/src/ops/euclid.rs @@ -48,8 +48,28 @@ pub trait Euclid: Sized + Div + Rem { fn rem_euclid(&self, v: &Self) -> Self; } +macro_rules! euclid_forward_impl { + ($($t:ty)*) => {$( + #[cfg(has_div_euclid)] + impl Euclid for $t { + #[inline] + fn div_euclid(&self, v: &$t) -> Self { + <$t>::div_euclid(*self, *v) + } + + #[inline] + fn rem_euclid(&self, v: &$t) -> Self { + <$t>::rem_euclid(*self, *v) + } + } + )*} +} + macro_rules! euclid_int_impl { ($($t:ty)*) => {$( + euclid_forward_impl!($t); + + #[cfg(not(has_div_euclid))] impl Euclid for $t { #[inline] fn div_euclid(&self, v: &$t) -> Self { @@ -79,6 +99,9 @@ macro_rules! euclid_int_impl { macro_rules! euclid_uint_impl { ($($t:ty)*) => {$( + euclid_forward_impl!($t); + + #[cfg(not(has_div_euclid))] impl Euclid for $t { #[inline] fn div_euclid(&self, v: &$t) -> Self { @@ -100,6 +123,10 @@ euclid_int_impl!(i128); #[cfg(has_i128)] euclid_uint_impl!(u128); +#[cfg(all(has_div_euclid, feature = "std"))] +euclid_forward_impl!(f32 f64); + +#[cfg(not(all(has_div_euclid, feature = "std")))] impl Euclid for f32 { #[inline] fn div_euclid(&self, v: &f32) -> f32 { @@ -121,6 +148,7 @@ impl Euclid for f32 { } } +#[cfg(not(all(has_div_euclid, feature = "std")))] impl Euclid for f64 { #[inline] fn div_euclid(&self, v: &f64) -> f64 { @@ -152,8 +180,28 @@ pub trait CheckedEuclid: Euclid { fn checked_rem_euclid(&self, v: &Self) -> Option; } +macro_rules! checked_euclid_forward_impl { + ($($t:ty)*) => {$( + #[cfg(has_div_euclid)] + impl CheckedEuclid for $t { + #[inline] + fn checked_div_euclid(&self, v: &$t) -> Option { + <$t>::checked_div_euclid(*self, *v) + } + + #[inline] + fn checked_rem_euclid(&self, v: &$t) -> Option { + <$t>::checked_rem_euclid(*self, *v) + } + } + )*} +} + macro_rules! checked_euclid_int_impl { ($($t:ty)*) => {$( + checked_euclid_forward_impl!($t); + + #[cfg(not(has_div_euclid))] impl CheckedEuclid for $t { #[inline] fn checked_div_euclid(&self, v: &$t) -> Option<$t> { @@ -178,6 +226,9 @@ macro_rules! checked_euclid_int_impl { macro_rules! checked_euclid_uint_impl { ($($t:ty)*) => {$( + checked_euclid_forward_impl!($t); + + #[cfg(not(has_div_euclid))] impl CheckedEuclid for $t { #[inline] fn checked_div_euclid(&self, v: &$t) -> Option<$t> {