diff --git a/benches/gcd.rs b/benches/gcd.rs index 8fa99bc..082d5ee 100644 --- a/benches/gcd.rs +++ b/benches/gcd.rs @@ -115,7 +115,7 @@ impl_gcd_old_for_usize!(usize); impl_gcd_old_for_usize!(u128); /// Return an iterator that yields all Fibonacci numbers fitting into a u128. -fn fibonacci() -> impl Iterator { +fn fibonacci() -> impl Iterator { (0..185).scan((0, 1), |&mut (ref mut a, ref mut b), _| { let tmp = *a; *a = *b; diff --git a/benches/roots.rs b/benches/roots.rs index 3ca8015..7f67278 100644 --- a/benches/roots.rs +++ b/benches/roots.rs @@ -13,11 +13,7 @@ use test::{black_box, Bencher}; trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} -impl BenchInteger for T -where - T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static, -{ -} +impl BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} fn bench(b: &mut Bencher, v: &[T], f: F, n: u32) where diff --git a/src/lib.rs b/src/lib.rs index 41e0139..39e9de5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ //! The `num-integer` crate is tested for rustc 1.8 and greater. #![doc(html_root_url = "https://docs.rs/num-integer/0.1")] - #![no_std] #[cfg(feature = "std")] extern crate std; @@ -24,11 +23,11 @@ extern crate num_traits as traits; use core::ops::Add; -use traits::{Num, Signed}; +use traits::{Num, Signed, Zero}; mod roots; pub use roots::Roots; -pub use roots::{sqrt, cbrt, nth_root}; +pub use roots::{cbrt, nth_root, sqrt}; pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// Floored integer division. @@ -92,6 +91,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # use num_integer::Integer; /// assert_eq!(7.lcm(&3), 21); /// assert_eq!(2.lcm(&4), 4); + /// assert_eq!(0.lcm(&0), 0); /// ~~~ fn lcm(&self, other: &Self) -> Self; @@ -207,17 +207,18 @@ pub fn lcm(x: T, y: T) -> T { } macro_rules! impl_integer_for_isize { - ($T:ty, $test_mod:ident) => ( + ($T:ty, $test_mod:ident) => { impl Integer for $T { /// Floored integer division #[inline] fn div_floor(&self, other: &Self) -> Self { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => d - 1, - (d, _) => d, + let (d, r) = self.div_rem(other); + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + d - 1 + } else { + d } } @@ -226,10 +227,11 @@ macro_rules! impl_integer_for_isize { fn mod_floor(&self, other: &Self) -> Self { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match *self % *other { - r if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => r + *other, - r => r, + let r = *self % *other; + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + r + *other + } else { + r } } @@ -238,10 +240,11 @@ macro_rules! impl_integer_for_isize { fn div_mod_floor(&self, other: &Self) -> (Self, Self) { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => (d - 1, r + *other), - (d, r) => (d, r), + let (d, r) = self.div_rem(other); + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + (d - 1, r + *other) + } else { + (d, r) } } @@ -252,7 +255,9 @@ macro_rules! impl_integer_for_isize { // Use Stein's algorithm let mut m = *self; let mut n = *other; - if m == 0 || n == 0 { return (m | n).abs() } + if m == 0 || n == 0 { + return (m | n).abs(); + } // find common factors of 2 let shift = (m | n).trailing_zeros(); @@ -266,7 +271,7 @@ macro_rules! impl_integer_for_isize { // is positive for all numbers except gcd = abs(min value) // The call to .abs() causes a panic in debug mode if m == Self::min_value() || n == Self::min_value() { - return (1 << shift).abs() + return (1 << shift).abs(); } // guaranteed to be positive now, rest like unsigned algorithm @@ -293,8 +298,12 @@ macro_rules! impl_integer_for_isize { /// `other`. #[inline] fn lcm(&self, other: &Self) -> Self { - // should not have to recalculate abs - (*self * (*other / self.gcd(other))).abs() + if self.is_zero() && other.is_zero() { + Self::zero() + } else { + // should not have to recalculate abs + (*self * (*other / self.gcd(other))).abs() + } } /// Deprecated, use `is_multiple_of` instead. @@ -311,11 +320,15 @@ macro_rules! impl_integer_for_isize { /// Returns `true` if the number is divisible by `2` #[inline] - fn is_even(&self) -> bool { (*self) & 1 == 0 } + fn is_even(&self) -> bool { + (*self) & 1 == 0 + } /// Returns `true` if the number is not divisible by `2` #[inline] - fn is_odd(&self) -> bool { !self.is_even() } + fn is_odd(&self) -> bool { + !self.is_even() + } /// Simultaneous truncated integer division and modulus. #[inline] @@ -326,8 +339,8 @@ macro_rules! impl_integer_for_isize { #[cfg(test)] mod $test_mod { - use Integer; use core::mem; + use Integer; /// Checks that the division rule holds for: /// @@ -335,14 +348,14 @@ macro_rules! impl_integer_for_isize { /// - `d`: denominator (divisor) /// - `qr`: quotient and remainder #[cfg(test)] - fn test_division_rule((n,d): ($T, $T), (q,r): ($T, $T)) { + fn test_division_rule((n, d): ($T, $T), (q, r): ($T, $T)) { assert_eq!(d * q + r, n); } #[test] fn test_div_rem() { - fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) { - let (n,d) = nd; + fn test_nd_dr(nd: ($T, $T), qr: ($T, $T)) { + let (n, d) = nd; let separate_div_rem = (n / d, n % d); let combined_div_rem = n.div_rem(&d); @@ -353,21 +366,21 @@ macro_rules! impl_integer_for_isize { test_division_rule(nd, combined_div_rem); } - test_nd_dr(( 8, 3), ( 2, 2)); - test_nd_dr(( 8, -3), (-2, 2)); - test_nd_dr((-8, 3), (-2, -2)); - test_nd_dr((-8, -3), ( 2, -2)); + test_nd_dr((8, 3), (2, 2)); + test_nd_dr((8, -3), (-2, 2)); + test_nd_dr((-8, 3), (-2, -2)); + test_nd_dr((-8, -3), (2, -2)); - test_nd_dr(( 1, 2), ( 0, 1)); - test_nd_dr(( 1, -2), ( 0, 1)); - test_nd_dr((-1, 2), ( 0, -1)); - test_nd_dr((-1, -2), ( 0, -1)); + test_nd_dr((1, 2), (0, 1)); + test_nd_dr((1, -2), (0, 1)); + test_nd_dr((-1, 2), (0, -1)); + test_nd_dr((-1, -2), (0, -1)); } #[test] fn test_div_mod_floor() { - fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) { - let (n,d) = nd; + fn test_nd_dm(nd: ($T, $T), dm: ($T, $T)) { + let (n, d) = nd; let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); let combined_div_mod_floor = n.div_mod_floor(&d); @@ -378,15 +391,15 @@ macro_rules! impl_integer_for_isize { test_division_rule(nd, combined_div_mod_floor); } - test_nd_dm(( 8, 3), ( 2, 2)); - test_nd_dm(( 8, -3), (-3, -1)); - test_nd_dm((-8, 3), (-3, 1)); - test_nd_dm((-8, -3), ( 2, -2)); + test_nd_dm((8, 3), (2, 2)); + test_nd_dm((8, -3), (-3, -1)); + test_nd_dm((-8, 3), (-3, 1)); + test_nd_dm((-8, -3), (2, -2)); - test_nd_dm(( 1, 2), ( 0, 1)); - test_nd_dm(( 1, -2), (-1, -1)); - test_nd_dm((-1, 2), (-1, 1)); - test_nd_dm((-1, -2), ( 0, -1)); + test_nd_dm((1, 2), (0, 1)); + test_nd_dm((1, -2), (-1, -1)); + test_nd_dm((-1, 2), (-1, 1)); + test_nd_dm((-1, -2), (0, -1)); } #[test] @@ -416,7 +429,7 @@ macro_rules! impl_integer_for_isize { // for i8 for i in -127..127 { for j in -127..127 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } } @@ -424,7 +437,7 @@ macro_rules! impl_integer_for_isize { // FIXME: Use inclusive ranges for above loop when implemented let i = 127; for j in -127..127 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } assert_eq!(127.gcd(&127), 127); } @@ -501,7 +514,7 @@ macro_rules! impl_integer_for_isize { assert_eq!((4 as $T).is_odd(), false); } } - ) + }; } impl_integer_for_isize!(i8, test_integer_i8); @@ -513,7 +526,7 @@ impl_integer_for_isize!(isize, test_integer_isize); impl_integer_for_isize!(i128, test_integer_i128); macro_rules! impl_integer_for_usize { - ($T:ty, $test_mod:ident) => ( + ($T:ty, $test_mod:ident) => { impl Integer for $T { /// Unsigned integer division. Returns the same result as `div` (`/`). #[inline] @@ -533,7 +546,9 @@ macro_rules! impl_integer_for_usize { // Use Stein's algorithm let mut m = *self; let mut n = *other; - if m == 0 || n == 0 { return m | n } + if m == 0 || n == 0 { + return m | n; + } // find common factors of 2 let shift = (m | n).trailing_zeros(); @@ -557,7 +572,11 @@ macro_rules! impl_integer_for_usize { /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. #[inline] fn lcm(&self, other: &Self) -> Self { - *self * (*other / self.gcd(other)) + if self.is_zero() && other.is_zero() { + Self::zero() + } else { + *self * (*other / self.gcd(other)) + } } /// Deprecated, use `is_multiple_of` instead. @@ -593,8 +612,8 @@ macro_rules! impl_integer_for_usize { #[cfg(test)] mod $test_mod { - use Integer; use core::mem; + use Integer; #[test] fn test_div_mod_floor() { @@ -630,7 +649,7 @@ macro_rules! impl_integer_for_usize { for i in 0..255 { for j in 0..255 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } } @@ -638,7 +657,7 @@ macro_rules! impl_integer_for_usize { // FIXME: Use inclusive ranges for above loop when implemented let i = 255; for j in 0..255 { - assert_eq!(euclidean_gcd(i,j), i.gcd(&j)); + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); } assert_eq!(255.gcd(&255), 255); } @@ -678,7 +697,7 @@ macro_rules! impl_integer_for_usize { assert_eq!((4 as $T).is_odd(), false); } } - ) + }; } impl_integer_for_usize!(u8, test_integer_u8); @@ -697,7 +716,8 @@ pub struct IterBinomial { } impl IterBinomial - where T: Integer, +where + T: Integer, { /// For a given n, iterate over all binomial coefficients binomial(n, k), for k=0...n. /// @@ -719,13 +739,16 @@ impl IterBinomial /// For larger n, `T` should be a bigint type. pub fn new(n: T) -> IterBinomial { IterBinomial { - k: T::zero(), a: T::one(), n: n + k: T::zero(), + a: T::one(), + n: n, } } } impl Iterator for IterBinomial - where T: Integer + Clone +where + T: Integer + Clone, { type Item = T; @@ -737,7 +760,7 @@ impl Iterator for IterBinomial multiply_and_divide( self.a.clone(), self.n.clone() - self.k.clone() + T::one(), - self.k.clone() + self.k.clone(), ) } else { T::one() @@ -753,7 +776,7 @@ impl Iterator for IterBinomial fn multiply_and_divide(r: T, a: T, b: T) -> T { // See http://blog.plover.com/math/choose-2.html for the idea. let g = gcd(r.clone(), b.clone()); - r/g.clone() * (a / (b/g)) + r / g.clone() * (a / (b / g)) } /// Calculate the binomial coefficient. @@ -797,7 +820,8 @@ pub fn binomial(mut n: T, k: T) -> T { /// Calculate the multinomial coefficient. pub fn multinomial(k: &[T]) -> T - where for<'a> T: Add<&'a T, Output = T> +where + for<'a> T: Add<&'a T, Output = T>, { let mut r = T::one(); let mut p = T::zero(); @@ -811,16 +835,20 @@ pub fn multinomial(k: &[T]) -> T #[test] fn test_lcm_overflow() { macro_rules! check { - ($t:ty, $x:expr, $y:expr, $r:expr) => { { + ($t:ty, $x:expr, $y:expr, $r:expr) => {{ let x: $t = $x; let y: $t = $y; let o = x.checked_mul(y); - assert!(o.is_none(), - "sanity checking that {} input {} * {} overflows", - stringify!($t), x, y); + assert!( + o.is_none(), + "sanity checking that {} input {} * {} overflows", + stringify!($t), + x, + y + ); assert_eq!(x.lcm(&y), $r); assert_eq!(y.lcm(&x), $r); - } } + }}; } // Original bug (Issue #166) @@ -839,13 +867,13 @@ fn test_lcm_overflow() { #[test] fn test_iter_binomial() { macro_rules! check_simple { - ($t:ty) => { { + ($t:ty) => {{ let n: $t = 3; let expected = [1, 3, 3, 1]; for (b, &e) in IterBinomial::new(n).zip(&expected) { assert_eq!(b, e); } - } } + }}; } check_simple!(u8); @@ -858,14 +886,14 @@ fn test_iter_binomial() { check_simple!(i64); macro_rules! check_binomial { - ($t:ty, $n:expr) => { { + ($t:ty, $n:expr) => {{ let n: $t = $n; let mut k: $t = 0; for b in IterBinomial::new(n) { assert_eq!(b, binomial(n, k)); k += 1; } - } } + }}; } // Check the largest n for which there is no overflow. @@ -882,7 +910,7 @@ fn test_iter_binomial() { #[test] fn test_binomial() { macro_rules! check { - ($t:ty, $x:expr, $y:expr, $r:expr) => { { + ($t:ty, $x:expr, $y:expr, $r:expr) => {{ let x: $t = $x; let y: $t = $y; let expected: $t = $r; @@ -890,7 +918,7 @@ fn test_binomial() { if y <= x { assert_eq!(binomial(x, x - y), expected); } - } } + }}; } check!(u8, 9, 4, 126); check!(u8, 0, 0, 1); @@ -938,12 +966,12 @@ fn test_binomial() { #[test] fn test_multinomial() { macro_rules! check_binomial { - ($t:ty, $k:expr) => { { + ($t:ty, $k:expr) => {{ let n: $t = $k.iter().fold(0, |acc, &x| acc + x); let k: &[$t] = $k; assert_eq!(k.len(), 2); assert_eq!(multinomial(k), binomial(n, k[0])); - } } + }}; } check_binomial!(u8, &[4, 5]); @@ -973,11 +1001,11 @@ fn test_multinomial() { check_binomial!(i64, &[4, 10]); macro_rules! check_multinomial { - ($t:ty, $k:expr, $r:expr) => { { + ($t:ty, $k:expr, $r:expr) => {{ let k: &[$t] = $k; let expected: $t = $r; assert_eq!(multinomial(k), expected); - } } + }}; } check_multinomial!(u8, &[2, 1, 2], 30); diff --git a/tests/roots.rs b/tests/roots.rs index 85e97f3..f85f9e0 100644 --- a/tests/roots.rs +++ b/tests/roots.rs @@ -10,11 +10,7 @@ use std::mem; trait TestInteger: Roots + PrimInt + Debug + AsPrimitive + 'static {} -impl TestInteger for T -where - T: Roots + PrimInt + Debug + AsPrimitive + 'static, -{ -} +impl TestInteger for T where T: Roots + PrimInt + Debug + AsPrimitive + 'static {} /// Check that each root is correct ///