// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
//! Integer trait and functions. //! //! ## Compatibility //! //! The `num-integer` crate is tested for rustc 1.8 and greater.
/// Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) together. /// /// Potentially more efficient than calling `gcd` and `lcm` /// individually for identical inputs. /// /// # Examples /// /// ~~~ /// # use num_integer::Integer; /// assert_eq!(10.gcd_lcm(&4), (2, 20)); /// assert_eq!(8.gcd_lcm(&9), (1, 72)); /// ~~~ #[inline] fn gcd_lcm(&self, other: &Self) -> (Self, Self) {
(self.gcd(other), self.lcm(other))
}
/// Greatest common divisor and Bézout coefficients. /// /// # Examples /// /// ~~~ /// # extern crate num_integer; /// # extern crate num_traits; /// # fn main() { /// # use num_integer::{ExtendedGcd, Integer}; /// # use num_traits::NumAssign; /// fn check<A: Copy + Integer + NumAssign>(a: A, b: A) -> bool { /// let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b); /// gcd == x * a + y * b /// } /// assert!(check(10isize, 4isize)); /// assert!(check(8isize, 9isize)); /// # } /// ~~~ #[inline] fn extended_gcd(&self, other: &Self) -> ExtendedGcd<Self> where Self: Clone,
{ letmut s = (Self::zero(), Self::one()); letmut t = (Self::one(), Self::zero()); letmut r = (other.clone(), self.clone());
while !r.0.is_zero() { let q = r.1.clone() / r.0.clone(); let f = |mut r: (Self, Self)| {
mem::swap(&mut r.0, &mut r.1);
r.0 = r.0 - q.clone() * r.1.clone();
r
};
r = f(r);
s = f(s);
t = f(t);
}
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The /// result is always non-negative. #[inline(always)] pubfn gcd<T: Integer>(x: T, y: T) -> T {
x.gcd(&y)
} /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. #[inline(always)] pubfn lcm<T: Integer>(x: T, y: T) -> T {
x.lcm(&y)
}
/// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`. #[inline(always)] pubfn gcd_lcm<T: Integer>(x: T, y: T) -> (T, T) {
x.gcd_lcm(&y)
}
macro_rules! impl_integer_for_isize {
($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) let (d, r) = self.div_rem(other); if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
d - 1
} else {
d
}
}
/// Floored integer modulo #[inline] 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) let r = *self % *other; if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
r + *other
} else {
r
}
}
/// Calculates `div_floor` and `mod_floor` simultaneously #[inline] 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) let (d, r) = self.div_rem(other); if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
(d - 1, r + *other)
} else {
(d, r)
}
}
#[inline] fn div_ceil(&self, other: &Self) -> Self { let (d, r) = self.div_rem(other); if (r > 0 && *other > 0) || (r < 0 && *other < 0) {
d + 1
} else {
d
}
}
/// Calculates the Greatest Common Divisor (GCD) of the number and /// `other`. The result is always non-negative. #[inline] fn gcd(&self, other: &Self) -> Self { // Use Stein's algorithm letmut m = *self; letmut n = *other; if m == 0 || n == 0 { return (m | n).abs();
}
// find common factors of 2 let shift = (m | n).trailing_zeros();
// The algorithm needs positive numbers, but the minimum value // can't be represented as a positive one. // It's also a power of two, so the gcd can be // calculated by bitshifting in that case
// Assuming two's complement, the number created by the shift // 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();
}
// guaranteed to be positive now, rest like unsigned algorithm
m = m.abs();
n = n.abs();
// divide n and m by 2 until odd
m >>= m.trailing_zeros();
n >>= n.trailing_zeros();
while m != n { if m > n {
m -= n;
m >>= m.trailing_zeros();
} else {
n -= m;
n >>= n.trailing_zeros();
}
}
m << shift
}
#[inline] fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd<Self>, Self) { let egcd = self.extended_gcd(other); // should not have to recalculate abs let lcm = if egcd.gcd.is_zero() { Self::zero()
} else {
(*self * (*other / egcd.gcd)).abs()
};
(egcd, lcm)
}
/// Calculates the Lowest Common Multiple (LCM) of the number and /// `other`. #[inline] fn lcm(&self, other: &Self) -> Self { self.gcd_lcm(other).1
}
/// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`. #[inline] fn gcd_lcm(&self, other: &Self) -> (Self, Self) { ifself.is_zero() && other.is_zero() { return (Self::zero(), Self::zero());
} let gcd = self.gcd(other); // should not have to recalculate abs let lcm = (*self * (*other / gcd)).abs();
(gcd, lcm)
}
/// Returns `true` if the number is a multiple of `other`. #[inline] fn is_multiple_of(&self, other: &Self) -> bool { if other.is_zero() { returnself.is_zero();
}
*self % *other == 0
}
/// Returns `true` if the number is divisible by `2` #[inline] 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()
}
#[test] fn test_gcd_cmp_with_euclidean() { fn euclidean_gcd(mut m: $T, mut n: $T) -> $T { while m != 0 {
mem::swap(&mut m, &mut n);
m %= n;
}
n.abs()
}
// gcd(-128, b) = 128 is not representable as positive value // for i8 for i in -127..127 { for j in -127..127 {
assert_eq!(euclidean_gcd(i, j), i.gcd(&j));
}
}
// last value // 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!(127.gcd(&127), 127);
}
#[test] fn test_gcd_min_val() { let min = <$T>::min_value(); let max = <$T>::max_value(); let max_pow2 = max / 2 + 1;
assert_eq!(min.gcd(&max), 1as $T);
assert_eq!(max.gcd(&min), 1as $T);
assert_eq!(min.gcd(&max_pow2), max_pow2);
assert_eq!(max_pow2.gcd(&min), max_pow2);
assert_eq!(min.gcd(&42), 2as $T);
assert_eq!((42as $T).gcd(&min), 2as $T);
}
#[test] #[should_panic] fn test_gcd_min_val_min_val() { let min = <$T>::min_value();
assert!(min.gcd(&min) >= 0);
}
#[test] #[should_panic] fn test_gcd_min_val_0() { let min = <$T>::min_value();
assert!(min.gcd(&0) >= 0);
}
#[test] #[should_panic] fn test_gcd_0_min_val() { let min = <$T>::min_value();
assert!((0as $T).gcd(&min) >= 0);
}
#[test] fn test_gcd_lcm() { use core::iter::once; for i in once(0)
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
.chain(once(-128))
{ for j in once(0)
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
.chain(once(-128))
{
assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j)));
}
}
}
#[test] fn test_extended_gcd_lcm() { use core::fmt::Debug; use traits::NumAssign; use ExtendedGcd;
fn check<A: Copy + Debug + Integer + NumAssign>(a: A, b: A) { let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b);
assert_eq!(gcd, x * a + y * b);
}
use core::iter::once; for i in once(0)
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
.chain(once(-128))
{ for j in once(0)
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
.chain(once(-128))
{
check(i, j); let (ExtendedGcd { gcd, .. }, lcm) = i.extended_gcd_lcm(&j);
assert_eq!((gcd, lcm), (i.gcd(&j), i.lcm(&j)));
}
}
}
#[test] fn test_multiple_of_one_limits() { for x in &[<$T>::min_value(), <$T>::max_value()] { for one in &[1, -1] {
assert_eq!(Integer::next_multiple_of(x, one), *x);
assert_eq!(Integer::prev_multiple_of(x, one), *x);
}
}
}
}
};
}
/// Calculates the Greatest Common Divisor (GCD) of the number and `other` #[inline] fn gcd(&self, other: &Self) -> Self { // Use Stein's algorithm letmut m = *self; letmut n = *other; if m == 0 || n == 0 { return m | n;
}
// find common factors of 2 let shift = (m | n).trailing_zeros();
// divide n and m by 2 until odd
m >>= m.trailing_zeros();
n >>= n.trailing_zeros();
while m != n { if m > n {
m -= n;
m >>= m.trailing_zeros();
} else {
n -= m;
n >>= n.trailing_zeros();
}
}
m << shift
}
#[inline] fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd<Self>, Self) { let egcd = self.extended_gcd(other); // should not have to recalculate abs let lcm = if egcd.gcd.is_zero() { Self::zero()
} else {
*self * (*other / egcd.gcd)
};
(egcd, lcm)
}
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`. #[inline] fn lcm(&self, other: &Self) -> Self { self.gcd_lcm(other).1
}
/// Calculates the Greatest Common Divisor (GCD) and /// Lowest Common Multiple (LCM) of the number and `other`. #[inline] fn gcd_lcm(&self, other: &Self) -> (Self, Self) { ifself.is_zero() && other.is_zero() { return (Self::zero(), Self::zero());
} let gcd = self.gcd(other); let lcm = *self * (*other / gcd);
(gcd, lcm)
}
/// Returns `true` if the number is a multiple of `other`. #[inline] fn is_multiple_of(&self, other: &Self) -> bool { if other.is_zero() { returnself.is_zero();
}
*self % *other == 0
}
/// Returns `true` if the number is divisible by `2`. #[inline] fn is_even(&self) -> bool {
*self % 2 == 0
}
/// Returns `true` if the number is not divisible by `2`. #[inline] fn is_odd(&self) -> bool {
!self.is_even()
}
#[test] fn test_gcd_cmp_with_euclidean() { fn euclidean_gcd(mut m: $T, mut n: $T) -> $T { while m != 0 {
mem::swap(&mut m, &mut n);
m %= n;
}
n
}
for i in0..255 { for j in0..255 {
assert_eq!(euclidean_gcd(i, j), i.gcd(&j));
}
}
// last value // FIXME: Use inclusive ranges for above loop when implemented let i = 255; for j in0..255 {
assert_eq!(euclidean_gcd(i, j), i.gcd(&j));
}
assert_eq!(255.gcd(&255), 255);
}
/// An iterator over binomial coefficients. pubstruct IterBinomial<T> {
a: T,
n: T,
k: T,
}
impl<T> IterBinomial<T> where
T: Integer,
{ /// For a given n, iterate over all binomial coefficients binomial(n, k), for k=0...n. /// /// Note that this might overflow, depending on `T`. For the primitive /// integer types, the following n are the largest ones for which there will /// be no overflow: /// /// type | n /// -----|--- /// u8 | 10 /// i8 | 9 /// u16 | 18 /// i16 | 17 /// u32 | 34 /// i32 | 33 /// u64 | 67 /// i64 | 66 /// /// For larger n, `T` should be a bigint type. pubfn new(n: T) -> IterBinomial<T> {
IterBinomial {
k: T::zero(),
a: T::one(),
n: n,
}
}
}
impl<T> Iterator for IterBinomial<T> where
T: Integer + Clone,
{ type Item = T;
/// Calculate r * a / b, avoiding overflows and fractions. /// /// Assumes that b divides r * a evenly. fn multiply_and_divide<T: Integer + Clone>(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))
}
/// Calculate the binomial coefficient. /// /// Note that this might overflow, depending on `T`. For the primitive integer /// types, the following n are the largest ones possible such that there will /// be no overflow for any k: /// /// type | n /// -----|--- /// u8 | 10 /// i8 | 9 /// u16 | 18 /// i16 | 17 /// u32 | 34 /// i32 | 33 /// u64 | 67 /// i64 | 66 /// /// For larger n, consider using a bigint type for `T`. pubfn binomial<T: Integer + Clone>(mut n: T, k: T) -> T { // See http://blog.plover.com/math/choose.html for the idea. if k > n { return T::zero();
} if k > n.clone() - k.clone() { return binomial(n.clone(), n - k);
} letmut r = T::one(); letmut d = T::one(); loop { if d > k { break;
}
r = multiply_and_divide(r, n.clone(), d.clone());
n = n - T::one();
d = d + T::one();
}
r
}
/// Calculate the multinomial coefficient. pubfn multinomial<T: Integer + Clone>(k: &[T]) -> T where for<'a> T: Add<&'a T, Output = T>,
{ letmut r = T::one(); letmut p = T::zero(); for i in k {
p = p + i;
r = r * binomial(p.clone(), i.clone());
}
r
}
#[test] fn test_lcm_overflow() {
macro_rules! check {
($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_eq!(x.lcm(&y), $r);
assert_eq!(y.lcm(&x), $r);
}};
}
// Original bug (Issue #166)
check!(i64, 46656000000000000, 600, 46656000000000000);
macro_rules! check_binomial {
($t:ty, $n:expr) => {{ let n: $t = $n; letmut 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.
check_binomial!(u8, 10);
check_binomial!(i8, 9);
check_binomial!(u16, 18);
check_binomial!(i16, 17);
check_binomial!(u32, 34);
check_binomial!(i32, 33);
check_binomial!(u64, 67);
check_binomial!(i64, 66);
}
#[test] fn test_binomial() {
macro_rules! check {
($t:ty, $x:expr, $y:expr, $r:expr) => {{ let x: $t = $x; let y: $t = $y; let expected: $t = $r;
assert_eq!(binomial(x, y), expected); if y <= x {
assert_eq!(binomial(x, x - y), expected);
}
}};
}
check!(u8, 9, 4, 126);
check!(u8, 0, 0, 1);
check!(u8, 2, 3, 0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.