From 3a9eca3a7be3ea156147fb8ed00a6447112e74d7 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 17 Feb 2014 07:20:01 +1100 Subject: [PATCH] Move std::num::Integer to libnum --- src/etc/vim/syntax/rust.vim | 2 +- src/libnum/bigint.rs | 8 +- src/libnum/lib.rs | 400 ++++++++++++++++++++++++++++ src/libnum/rational.rs | 2 + src/libstd/iter.rs | 14 +- src/libstd/num/int_macros.rs | 264 +----------------- src/libstd/num/mod.rs | 34 +-- src/libstd/num/strconv.rs | 16 +- src/libstd/num/uint_macros.rs | 111 -------- src/libstd/prelude.rs | 2 +- src/libstd/vec.rs | 6 +- src/test/bench/shootout-pidigits.rs | 1 + 12 files changed, 439 insertions(+), 421 deletions(-) diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 511e0c9f74cc3..d17f8fc2d877e 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -85,7 +85,7 @@ syn keyword rustTrait Iterator DoubleEndedIterator RandomAccessIterator Cloneabl syn keyword rustTrait OrdIterator MutableDoubleEndedIterator ExactSize syn keyword rustTrait Algebraic Trigonometric Exponential Hyperbolic -syn keyword rustTrait Bitwise Bounded Integer +syn keyword rustTrait Bitwise Bounded Fractional syn keyword rustTrait Num NumCast CheckedAdd CheckedSub CheckedMul CheckedDiv syn keyword rustTrait Orderable Signed Unsigned Round syn keyword rustTrait Primitive Int Float ToStrRadix ToPrimitive FromPrimitive diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 21726d28e0ca2..0418c61d361b4 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -16,6 +16,8 @@ A `BigUint` is represented as an array of `BigDigit`s. A `BigInt` is a combination of `BigUint` and `Sign`. */ +use Integer; + use std::cmp; use std::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use std::num::{Zero, One, ToStrRadix, FromStrRadix}; @@ -461,7 +463,7 @@ impl Integer for BigUint { /// Returns `true` if the number can be divided by `other` without leaving a remainder #[inline] - fn is_multiple_of(&self, other: &BigUint) -> bool { (*self % *other).is_zero() } + fn divides(&self, other: &BigUint) -> bool { (*self % *other).is_zero() } /// Returns `true` if the number is divisible by `2` #[inline] @@ -1118,7 +1120,7 @@ impl Integer for BigInt { /// Returns `true` if the number can be divided by `other` without leaving a remainder #[inline] - fn is_multiple_of(&self, other: &BigInt) -> bool { self.data.is_multiple_of(&other.data) } + fn divides(&self, other: &BigInt) -> bool { self.data.divides(&other.data) } /// Returns `true` if the number is divisible by `2` #[inline] @@ -1388,6 +1390,7 @@ impl BigInt { #[cfg(test)] mod biguint_tests { + use Integer; use super::{BigDigit, BigUint, ToBigUint}; use super::{Plus, BigInt, RandBigInt, ToBigInt}; @@ -2045,6 +2048,7 @@ mod biguint_tests { #[cfg(test)] mod bigint_tests { + use Integer; use super::{BigDigit, BigUint, ToBigUint}; use super::{Sign, Minus, Zero, Plus, BigInt, RandBigInt, ToBigInt}; diff --git a/src/libnum/lib.rs b/src/libnum/lib.rs index 8d5338451bd93..e9e93cc29d6fe 100644 --- a/src/libnum/lib.rs +++ b/src/libnum/lib.rs @@ -20,3 +20,403 @@ extern crate extra; pub mod bigint; pub mod rational; pub mod complex; + +pub trait Integer: Num + Ord + + Div + + Rem { + /// Simultaneous truncated integer division and modulus + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self) { + (*self / *other, *self % *other) + } + + /// Floored integer division + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert!(( 8i).div_floor(& 3) == 2); + /// assert!(( 8i).div_floor(&-3) == -3); + /// assert!((-8i).div_floor(& 3) == -3); + /// assert!((-8i).div_floor(&-3) == 2); + /// + /// assert!(( 1i).div_floor(& 2) == 0); + /// assert!(( 1i).div_floor(&-2) == -1); + /// assert!((-1i).div_floor(& 2) == -1); + /// assert!((-1i).div_floor(&-2) == 0); + /// ~~~ + fn div_floor(&self, other: &Self) -> Self; + + /// Floored integer modulo, satisfying: + /// + /// ~~~ + /// # use num::Integer; + /// # let n = 1i; let d = 1i; + /// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n) + /// ~~~ + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert!(( 8i).mod_floor(& 3) == 2); + /// assert!(( 8i).mod_floor(&-3) == -1); + /// assert!((-8i).mod_floor(& 3) == 1); + /// assert!((-8i).mod_floor(&-3) == -2); + /// + /// assert!(( 1i).mod_floor(& 2) == 1); + /// assert!(( 1i).mod_floor(&-2) == -1); + /// assert!((-1i).mod_floor(& 2) == 1); + /// assert!((-1i).mod_floor(&-2) == -1); + /// ~~~ + fn mod_floor(&self, other: &Self) -> Self; + + /// Simultaneous floored integer division and modulus + fn div_mod_floor(&self, other: &Self) -> (Self, Self) { + (self.div_floor(other), self.mod_floor(other)) + } + + /// Greatest Common Divisor (GCD) + fn gcd(&self, other: &Self) -> Self; + + /// Lowest Common Multiple (LCM) + fn lcm(&self, other: &Self) -> Self; + + /// Returns `true` if `other` divides evenly into `self` + fn divides(&self, other: &Self) -> bool; + + /// Returns `true` if the number is even + fn is_even(&self) -> bool; + + /// Returns `true` if the number is odd + fn is_odd(&self) -> bool; +} + +/// Simultaneous integer division and modulus +#[inline] pub fn div_rem(x: T, y: T) -> (T, T) { x.div_rem(&y) } +/// Floored integer division +#[inline] pub fn div_floor(x: T, y: T) -> T { x.div_floor(&y) } +/// Floored integer modulus +#[inline] pub fn mod_floor(x: T, y: T) -> T { x.mod_floor(&y) } +/// Simultaneous floored integer division and modulus +#[inline] pub fn div_mod_floor(x: T, y: T) -> (T, T) { x.div_mod_floor(&y) } + +/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The +/// result is always positive. +#[inline(always)] pub fn gcd(x: T, y: T) -> T { x.gcd(&y) } +/// Calculates the Lowest Common Multiple (LCM) of the number and `other`. +#[inline(always)] pub fn lcm(x: T, y: T) -> T { x.lcm(&y) } + +macro_rules! impl_integer_for_int { + ($T:ty, $test_mod:ident) => ( + impl Integer for $T { + /// Floored integer division + #[inline] + fn div_floor(&self, other: &$T) -> $T { + // 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, + } + } + + /// Floored integer modulo + #[inline] + fn mod_floor(&self, other: &$T) -> $T { + // 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, + } + } + + /// Calculates `div_floor` and `mod_floor` simultaneously + #[inline] + fn div_mod_floor(&self, other: &$T) -> ($T,$T) { + // 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), + } + } + + /// Calculates the Greatest Common Divisor (GCD) of the number and + /// `other`. The result is always positive. + #[inline] + fn gcd(&self, other: &$T) -> $T { + // Use Euclid's algorithm + let mut m = *self; + let mut n = *other; + while m != 0 { + let temp = m; + m = n % temp; + n = temp; + } + n.abs() + } + + /// Calculates the Lowest Common Multiple (LCM) of the number and + /// `other`. + #[inline] + fn lcm(&self, other: &$T) -> $T { + // should not have to recaluculate abs + ((*self * *other) / self.gcd(other)).abs() + } + + /// Returns `true` if the number can be divided by `other` without + /// leaving a remainder + #[inline] + fn divides(&self, other: &$T) -> bool { *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() } + } + + #[cfg(test)] + mod $test_mod { + use Integer; + + /// Checks that the division rule holds for: + /// + /// - `n`: numerator (dividend) + /// - `d`: denominator (divisor) + /// - `qr`: quotient and remainder + #[cfg(test)] + 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; + let separate_div_rem = (n / d, n % d); + let combined_div_rem = n.div_rem(&d); + + assert_eq!(separate_div_rem, qr); + assert_eq!(combined_div_rem, qr); + + test_division_rule(nd, separate_div_rem); + 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(( 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; + let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); + let combined_div_mod_floor = n.div_mod_floor(&d); + + assert_eq!(separate_div_mod_floor, dm); + assert_eq!(combined_div_mod_floor, dm); + + test_division_rule(nd, separate_div_mod_floor); + 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(( 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] + fn test_gcd() { + assert_eq!((10 as $T).gcd(&2), 2 as $T); + assert_eq!((10 as $T).gcd(&3), 1 as $T); + assert_eq!((0 as $T).gcd(&3), 3 as $T); + assert_eq!((3 as $T).gcd(&3), 3 as $T); + assert_eq!((56 as $T).gcd(&42), 14 as $T); + assert_eq!((3 as $T).gcd(&-3), 3 as $T); + assert_eq!((-6 as $T).gcd(&3), 3 as $T); + assert_eq!((-4 as $T).gcd(&-2), 2 as $T); + } + + #[test] + fn test_lcm() { + assert_eq!((1 as $T).lcm(&0), 0 as $T); + assert_eq!((0 as $T).lcm(&1), 0 as $T); + assert_eq!((1 as $T).lcm(&1), 1 as $T); + assert_eq!((-1 as $T).lcm(&1), 1 as $T); + assert_eq!((1 as $T).lcm(&-1), 1 as $T); + assert_eq!((-1 as $T).lcm(&-1), 1 as $T); + assert_eq!((8 as $T).lcm(&9), 72 as $T); + assert_eq!((11 as $T).lcm(&5), 55 as $T); + } + + #[test] + fn test_even() { + assert_eq!((-4 as $T).is_even(), true); + assert_eq!((-3 as $T).is_even(), false); + assert_eq!((-2 as $T).is_even(), true); + assert_eq!((-1 as $T).is_even(), false); + assert_eq!((0 as $T).is_even(), true); + assert_eq!((1 as $T).is_even(), false); + assert_eq!((2 as $T).is_even(), true); + assert_eq!((3 as $T).is_even(), false); + assert_eq!((4 as $T).is_even(), true); + } + + #[test] + fn test_odd() { + assert_eq!((-4 as $T).is_odd(), false); + assert_eq!((-3 as $T).is_odd(), true); + assert_eq!((-2 as $T).is_odd(), false); + assert_eq!((-1 as $T).is_odd(), true); + assert_eq!((0 as $T).is_odd(), false); + assert_eq!((1 as $T).is_odd(), true); + assert_eq!((2 as $T).is_odd(), false); + assert_eq!((3 as $T).is_odd(), true); + assert_eq!((4 as $T).is_odd(), false); + } + } + ) +} + +impl_integer_for_int!(i8, test_integer_i8) +impl_integer_for_int!(i16, test_integer_i16) +impl_integer_for_int!(i32, test_integer_i32) +impl_integer_for_int!(i64, test_integer_i64) +impl_integer_for_int!(int, test_integer_int) + +macro_rules! impl_integer_for_uint { + ($T:ty, $test_mod:ident) => ( + impl Integer for $T { + /// Unsigned integer division. Returns the same result as `div` (`/`). + #[inline] + fn div_floor(&self, other: &$T) -> $T { *self / *other } + + /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). + #[inline] + fn mod_floor(&self, other: &$T) -> $T { *self % *other } + + /// Calculates the Greatest Common Divisor (GCD) of the number and `other` + #[inline] + fn gcd(&self, other: &$T) -> $T { + // Use Euclid's algorithm + let mut m = *self; + let mut n = *other; + while m != 0 { + let temp = m; + m = n % temp; + n = temp; + } + n + } + + /// Calculates the Lowest Common Multiple (LCM) of the number and `other` + #[inline] + fn lcm(&self, other: &$T) -> $T { + (*self * *other) / self.gcd(other) + } + + /// Returns `true` if the number can be divided by `other` without leaving a remainder + #[inline] + fn divides(&self, other: &$T) -> bool { *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() } + } + + #[cfg(test)] + mod $test_mod { + use Integer; + + #[test] + fn test_div_mod_floor() { + assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T); + assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T); + assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T)); + assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T); + assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T); + assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T)); + assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T); + assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T); + assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T)); + } + + #[test] + fn test_gcd() { + assert_eq!((10 as $T).gcd(&2), 2 as $T); + assert_eq!((10 as $T).gcd(&3), 1 as $T); + assert_eq!((0 as $T).gcd(&3), 3 as $T); + assert_eq!((3 as $T).gcd(&3), 3 as $T); + assert_eq!((56 as $T).gcd(&42), 14 as $T); + } + + #[test] + fn test_lcm() { + assert_eq!((1 as $T).lcm(&0), 0 as $T); + assert_eq!((0 as $T).lcm(&1), 0 as $T); + assert_eq!((1 as $T).lcm(&1), 1 as $T); + assert_eq!((8 as $T).lcm(&9), 72 as $T); + assert_eq!((11 as $T).lcm(&5), 55 as $T); + assert_eq!((99 as $T).lcm(&17), 1683 as $T); + } + + #[test] + fn test_divides() { + assert!((6 as $T).divides(&(6 as $T))); + assert!((6 as $T).divides(&(3 as $T))); + assert!((6 as $T).divides(&(1 as $T))); + } + + #[test] + fn test_even() { + assert_eq!((0 as $T).is_even(), true); + assert_eq!((1 as $T).is_even(), false); + assert_eq!((2 as $T).is_even(), true); + assert_eq!((3 as $T).is_even(), false); + assert_eq!((4 as $T).is_even(), true); + } + + #[test] + fn test_odd() { + assert_eq!((0 as $T).is_odd(), false); + assert_eq!((1 as $T).is_odd(), true); + assert_eq!((2 as $T).is_odd(), false); + assert_eq!((3 as $T).is_odd(), true); + assert_eq!((4 as $T).is_odd(), false); + } + } + ) +} + +impl_integer_for_uint!(u8, test_integer_u8) +impl_integer_for_uint!(u16, test_integer_u16) +impl_integer_for_uint!(u32, test_integer_u32) +impl_integer_for_uint!(u64, test_integer_u64) +impl_integer_for_uint!(uint, test_integer_uint) diff --git a/src/libnum/rational.rs b/src/libnum/rational.rs index a483946322f80..5f1868b48c519 100644 --- a/src/libnum/rational.rs +++ b/src/libnum/rational.rs @@ -10,6 +10,8 @@ //! Rational numbers +use Integer; + use std::cmp; use std::from_str::FromStr; use std::num::{Zero,One,ToStrRadix,FromStrRadix,Round}; diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 7516a3ddf543e..5e919e4ac0a4d 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -65,7 +65,7 @@ the rest of the rust manuals. */ use cmp; -use num::{Zero, One, Integer, CheckedAdd, CheckedSub, Saturating, ToPrimitive}; +use num::{Zero, One, CheckedAdd, CheckedSub, Saturating, ToPrimitive, Int}; use option::{Option, Some, None}; use ops::{Add, Mul, Sub}; use cmp::{Eq, Ord}; @@ -2005,9 +2005,9 @@ impl + Ord + Clone + ToPrimitive> Iterator for Range { } } -/// `Integer` is required to ensure the range will be the same regardless of +/// `Int` is required to ensure the range will be the same regardless of /// the direction it is consumed. -impl DoubleEndedIterator for Range { +impl DoubleEndedIterator for Range { #[inline] fn next_back(&mut self) -> Option { if self.stop > self.state { @@ -2065,7 +2065,7 @@ impl + Eq + Ord + Clone + ToPrimitive> Iterator for RangeInclusi } } -impl + Integer + Ord + Clone + ToPrimitive> DoubleEndedIterator +impl + Int + Ord + Clone + ToPrimitive> DoubleEndedIterator for RangeInclusive { #[inline] fn next_back(&mut self) -> Option { @@ -2381,7 +2381,7 @@ mod tests { #[test] fn test_filter_map() { let mut it = count(0u, 1u).take(10) - .filter_map(|x| if x.is_even() { Some(x*x) } else { None }); + .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None }); assert_eq!(it.collect::<~[uint]>(), ~[0*0, 2*2, 4*4, 6*6, 8*8]); } @@ -2648,7 +2648,7 @@ mod tests { fn test_all() { let v: ~&[int] = ~&[1, 2, 3, 4, 5]; assert!(v.iter().all(|&x| x < 10)); - assert!(!v.iter().all(|&x| x.is_even())); + assert!(!v.iter().all(|&x| x % 2 == 0)); assert!(!v.iter().all(|&x| x > 100)); assert!(v.slice(0, 0).iter().all(|_| fail!())); } @@ -2657,7 +2657,7 @@ mod tests { fn test_any() { let v: ~&[int] = ~&[1, 2, 3, 4, 5]; assert!(v.iter().any(|&x| x < 10)); - assert!(v.iter().any(|&x| x.is_even())); + assert!(v.iter().any(|&x| x % 2 == 0)); assert!(!v.iter().any(|&x| x > 100)); assert!(!v.slice(0, 0).iter().any(|_| fail!())); } diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 3ecc6f32017ea..7f45b5deb187c 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -91,53 +91,48 @@ impl Mul<$T,$T> for $T { #[cfg(not(test))] impl Div<$T,$T> for $T { - /// - /// Integer division, truncated towards 0. As this behaviour reflects the underlying - /// machine implementation it is more efficient than `Integer::div_floor`. + /// Integer division, truncated towards 0. /// /// # Examples /// - /// ``` + /// ~~~ /// assert!( 8 / 3 == 2); /// assert!( 8 / -3 == -2); /// assert!(-8 / 3 == -2); /// assert!(-8 / -3 == 2); - + /// /// assert!( 1 / 2 == 0); /// assert!( 1 / -2 == 0); /// assert!(-1 / 2 == 0); /// assert!(-1 / -2 == 0); - /// ``` - /// + /// ~~~ #[inline] fn div(&self, other: &$T) -> $T { *self / *other } } #[cfg(not(test))] impl Rem<$T,$T> for $T { - /// /// Returns the integer remainder after division, satisfying: /// - /// ``` + /// ~~~ /// # let n = 1; /// # let d = 2; /// assert!((n / d) * d + (n % d) == n) - /// ``` + /// ~~~ /// /// # Examples /// - /// ``` + /// ~~~ /// assert!( 8 % 3 == 2); /// assert!( 8 % -3 == 2); /// assert!(-8 % 3 == -2); /// assert!(-8 % -3 == -2); - + /// /// assert!( 1 % 2 == 1); /// assert!( 1 % -2 == 1); /// assert!(-1 % 2 == -1); /// assert!(-1 % -2 == -1); - /// ``` - /// + /// ~~~ #[inline] fn rem(&self, other: &$T) -> $T { *self % *other } } @@ -189,125 +184,6 @@ impl Signed for $T { fn is_negative(&self) -> bool { *self < 0 } } -impl Integer for $T { - /// - /// Floored integer division - /// - /// # Examples - /// - /// ``` - /// assert!(( 8i).div_floor(& 3) == 2); - /// assert!(( 8i).div_floor(&-3) == -3); - /// assert!((-8i).div_floor(& 3) == -3); - /// assert!((-8i).div_floor(&-3) == 2); - /// - /// assert!(( 1i).div_floor(& 2) == 0); - /// assert!(( 1i).div_floor(&-2) == -1); - /// assert!((-1i).div_floor(& 2) == -1); - /// assert!((-1i).div_floor(&-2) == 0); - /// ``` - /// - #[inline] - fn div_floor(&self, other: &$T) -> $T { - // 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, - } - } - - /// - /// Integer modulo, satisfying: - /// - /// ``` - /// # let n = 1i; let d = 1i; - /// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n) - /// ``` - /// - /// # Examples - /// - /// ``` - /// assert!(( 8i).mod_floor(& 3) == 2); - /// assert!(( 8i).mod_floor(&-3) == -1); - /// assert!((-8i).mod_floor(& 3) == 1); - /// assert!((-8i).mod_floor(&-3) == -2); - /// - /// assert!(( 1i).mod_floor(& 2) == 1); - /// assert!(( 1i).mod_floor(&-2) == -1); - /// assert!((-1i).mod_floor(& 2) == 1); - /// assert!((-1i).mod_floor(&-2) == -1); - /// ``` - /// - #[inline] - fn mod_floor(&self, other: &$T) -> $T { - // 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, - } - } - - /// Calculates `div_floor` and `mod_floor` simultaneously - #[inline] - fn div_mod_floor(&self, other: &$T) -> ($T,$T) { - // 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), - } - } - - /// Calculates `div` (`/`) and `rem` (`%`) simultaneously - #[inline] - fn div_rem(&self, other: &$T) -> ($T,$T) { - (*self / *other, *self % *other) - } - - /// - /// Calculates the Greatest Common Divisor (GCD) of the number and `other` - /// - /// The result is always positive - /// - #[inline] - fn gcd(&self, other: &$T) -> $T { - // Use Euclid's algorithm - let mut m = *self; - let mut n = *other; - while m != 0 { - let temp = m; - m = n % temp; - n = temp; - } - n.abs() - } - - /// - /// Calculates the Lowest Common Multiple (LCM) of the number and `other` - /// - #[inline] - fn lcm(&self, other: &$T) -> $T { - ((*self * *other) / self.gcd(other)).abs() // should not have to recaluculate abs - } - - /// Returns `true` if the number can be divided by `other` without leaving a remainder - #[inline] - fn is_multiple_of(&self, other: &$T) -> bool { *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() } -} - #[cfg(not(test))] impl BitOr<$T,$T> for $T { #[inline] @@ -481,92 +357,6 @@ mod tests { assert!((-1 as $T).is_negative()); } - /// - /// Checks that the division rule holds for: - /// - /// - `n`: numerator (dividend) - /// - `d`: denominator (divisor) - /// - `qr`: quotient and remainder - /// - #[cfg(test)] - 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; - let separate_div_rem = (n / d, n % d); - let combined_div_rem = n.div_rem(&d); - - assert_eq!(separate_div_rem, qr); - assert_eq!(combined_div_rem, qr); - - test_division_rule(nd, separate_div_rem); - 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(( 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; - let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); - let combined_div_mod_floor = n.div_mod_floor(&d); - - assert_eq!(separate_div_mod_floor, dm); - assert_eq!(combined_div_mod_floor, dm); - - test_division_rule(nd, separate_div_mod_floor); - 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(( 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] - fn test_gcd() { - assert_eq!((10 as $T).gcd(&2), 2 as $T); - assert_eq!((10 as $T).gcd(&3), 1 as $T); - assert_eq!((0 as $T).gcd(&3), 3 as $T); - assert_eq!((3 as $T).gcd(&3), 3 as $T); - assert_eq!((56 as $T).gcd(&42), 14 as $T); - assert_eq!((3 as $T).gcd(&-3), 3 as $T); - assert_eq!((-6 as $T).gcd(&3), 3 as $T); - assert_eq!((-4 as $T).gcd(&-2), 2 as $T); - } - - #[test] - fn test_lcm() { - assert_eq!((1 as $T).lcm(&0), 0 as $T); - assert_eq!((0 as $T).lcm(&1), 0 as $T); - assert_eq!((1 as $T).lcm(&1), 1 as $T); - assert_eq!((-1 as $T).lcm(&1), 1 as $T); - assert_eq!((1 as $T).lcm(&-1), 1 as $T); - assert_eq!((-1 as $T).lcm(&-1), 1 as $T); - assert_eq!((8 as $T).lcm(&9), 72 as $T); - assert_eq!((11 as $T).lcm(&5), 55 as $T); - } - #[test] fn test_bitwise() { assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(&(0b1010 as $T))); @@ -577,42 +367,6 @@ mod tests { assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not()); } - #[test] - fn test_multiple_of() { - assert!((6 as $T).is_multiple_of(&(6 as $T))); - assert!((6 as $T).is_multiple_of(&(3 as $T))); - assert!((6 as $T).is_multiple_of(&(1 as $T))); - assert!((-8 as $T).is_multiple_of(&(4 as $T))); - assert!((8 as $T).is_multiple_of(&(-1 as $T))); - assert!((-8 as $T).is_multiple_of(&(-2 as $T))); - } - - #[test] - fn test_even() { - assert_eq!((-4 as $T).is_even(), true); - assert_eq!((-3 as $T).is_even(), false); - assert_eq!((-2 as $T).is_even(), true); - assert_eq!((-1 as $T).is_even(), false); - assert_eq!((0 as $T).is_even(), true); - assert_eq!((1 as $T).is_even(), false); - assert_eq!((2 as $T).is_even(), true); - assert_eq!((3 as $T).is_even(), false); - assert_eq!((4 as $T).is_even(), true); - } - - #[test] - fn test_odd() { - assert_eq!((-4 as $T).is_odd(), false); - assert_eq!((-3 as $T).is_odd(), true); - assert_eq!((-2 as $T).is_odd(), false); - assert_eq!((-1 as $T).is_odd(), true); - assert_eq!((0 as $T).is_odd(), false); - assert_eq!((1 as $T).is_odd(), true); - assert_eq!((2 as $T).is_odd(), false); - assert_eq!((3 as $T).is_odd(), true); - assert_eq!((4 as $T).is_odd(), false); - } - #[test] fn test_count_ones() { assert_eq!((0b0101100 as $T).count_ones(), 3); diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 8a417096c3ea7..332eb62b0c63a 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -33,6 +33,12 @@ pub trait Num: Eq + Zero + One + Div + Rem {} +/// Simultaneous division and remainder +#[inline] +pub fn div_rem + Rem>(x: T, y: T) -> (T, T) { + (x / y, x % y) +} + /// Defines an additive identity element for `Self`. /// /// # Deriving @@ -122,31 +128,6 @@ pub trait Signed: Num pub trait Unsigned: Num {} -pub trait Integer: Num - + Ord - + Div - + Rem { - fn div_rem(&self, other: &Self) -> (Self,Self); - - fn div_floor(&self, other: &Self) -> Self; - fn mod_floor(&self, other: &Self) -> Self; - fn div_mod_floor(&self, other: &Self) -> (Self,Self); - - fn gcd(&self, other: &Self) -> Self; - fn lcm(&self, other: &Self) -> Self; - - fn is_multiple_of(&self, other: &Self) -> bool; - fn is_even(&self) -> bool; - fn is_odd(&self) -> bool; -} - -/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. -/// -/// The result is always positive. -#[inline(always)] pub fn gcd(x: T, y: T) -> T { x.gcd(&y) } -/// Calculates the Lowest Common Multiple (LCM) of the number and `other`. -#[inline(always)] pub fn lcm(x: T, y: T) -> T { x.lcm(&y) } - /// A collection of rounding operations. pub trait Round { /// Return the largest integer less than or equal to a number. @@ -270,8 +251,7 @@ pub trait Primitive: Clone + Bounded {} /// A collection of traits relevant to primitive signed and unsigned integers -pub trait Int: Integer - + Primitive +pub trait Int: Primitive + Bitwise + CheckedAdd + CheckedSub diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 6be829f51d73c..bc79ec9a4af38 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -21,7 +21,7 @@ use str; use vec::{CloneableVector, ImmutableVector, MutableVector}; use vec::OwnedVector; use num; -use num::{NumCast, Zero, One, cast, Integer}; +use num::{NumCast, Zero, One, cast, Int}; use num::{Round, Float, FPNaN, FPInfinite, ToPrimitive}; pub enum ExponentFormat { @@ -133,19 +133,7 @@ static NAN_BUF: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8]; * # Failure * - Fails if `radix` < 2 or `radix` > 36. */ -pub fn int_to_str_bytes_common - +Neg - +Rem - +Mul>( - num: T, - radix: uint, - sign: SignFormat, - f: |u8|) { +pub fn int_to_str_bytes_common(num: T, radix: uint, sign: SignFormat, f: |u8|) { assert!(2 <= radix && radix <= 36); let _0: T = Zero::zero(); diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 4fc30b43895e4..33fcdcc426adf 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -100,60 +100,6 @@ impl Neg<$T> for $T { impl Unsigned for $T {} -impl Integer for $T { - /// Calculates `div` (`/`) and `rem` (`%`) simultaneously - #[inline] - fn div_rem(&self, other: &$T) -> ($T,$T) { - (*self / *other, *self % *other) - } - - /// Unsigned integer division. Returns the same result as `div` (`/`). - #[inline] - fn div_floor(&self, other: &$T) -> $T { *self / *other } - - /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). - #[inline] - fn mod_floor(&self, other: &$T) -> $T { *self % *other } - - /// Calculates `div_floor` and `mod_floor` simultaneously - #[inline] - fn div_mod_floor(&self, other: &$T) -> ($T,$T) { - (*self / *other, *self % *other) - } - - /// Calculates the Greatest Common Divisor (GCD) of the number and `other` - #[inline] - fn gcd(&self, other: &$T) -> $T { - // Use Euclid's algorithm - let mut m = *self; - let mut n = *other; - while m != 0 { - let temp = m; - m = n % temp; - n = temp; - } - n - } - - /// Calculates the Lowest Common Multiple (LCM) of the number and `other` - #[inline] - fn lcm(&self, other: &$T) -> $T { - (*self * *other) / self.gcd(other) - } - - /// Returns `true` if the number can be divided by `other` without leaving a remainder - #[inline] - fn is_multiple_of(&self, other: &$T) -> bool { *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() } -} - #[cfg(not(test))] impl BitOr<$T,$T> for $T { #[inline] @@ -309,63 +255,6 @@ mod tests { num::test_num(10 as $T, 2 as $T); } - #[test] - fn test_div_mod_floor() { - assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T); - assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T); - assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T)); - assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T); - assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T); - assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T)); - assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T); - assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T); - assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T)); - } - - #[test] - fn test_gcd() { - assert_eq!((10 as $T).gcd(&2), 2 as $T); - assert_eq!((10 as $T).gcd(&3), 1 as $T); - assert_eq!((0 as $T).gcd(&3), 3 as $T); - assert_eq!((3 as $T).gcd(&3), 3 as $T); - assert_eq!((56 as $T).gcd(&42), 14 as $T); - } - - #[test] - fn test_lcm() { - assert_eq!((1 as $T).lcm(&0), 0 as $T); - assert_eq!((0 as $T).lcm(&1), 0 as $T); - assert_eq!((1 as $T).lcm(&1), 1 as $T); - assert_eq!((8 as $T).lcm(&9), 72 as $T); - assert_eq!((11 as $T).lcm(&5), 55 as $T); - assert_eq!((99 as $T).lcm(&17), 1683 as $T); - } - - #[test] - fn test_multiple_of() { - assert!((6 as $T).is_multiple_of(&(6 as $T))); - assert!((6 as $T).is_multiple_of(&(3 as $T))); - assert!((6 as $T).is_multiple_of(&(1 as $T))); - } - - #[test] - fn test_even() { - assert_eq!((0 as $T).is_even(), true); - assert_eq!((1 as $T).is_even(), false); - assert_eq!((2 as $T).is_even(), true); - assert_eq!((3 as $T).is_even(), false); - assert_eq!((4 as $T).is_even(), true); - } - - #[test] - fn test_odd() { - assert_eq!((0 as $T).is_odd(), false); - assert_eq!((1 as $T).is_odd(), true); - assert_eq!((2 as $T).is_odd(), false); - assert_eq!((3 as $T).is_odd(), true); - assert_eq!((4 as $T).is_odd(), false); - } - #[test] fn test_bitwise() { assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(&(0b1010 as $T))); diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 3f61f2484a57e..8fc4b985359e8 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -49,7 +49,7 @@ pub use hash::Hash; pub use iter::{FromIterator, Extendable}; pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator}; pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize}; -pub use num::{Integer, Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; +pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; pub use num::{Signed, Unsigned, Round}; pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive}; pub use path::{GenericPath, Path, PosixPath, WindowsPath}; diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 5a42df0a38937..0adc6083f6b81 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -111,7 +111,7 @@ use cmp; use default::Default; use fmt; use iter::*; -use num::{Integer, CheckedAdd, Saturating, checked_next_power_of_two}; +use num::{CheckedAdd, Saturating, checked_next_power_of_two, div_rem}; use option::{None, Option, Some}; use ptr; use ptr::RawPtr; @@ -575,7 +575,7 @@ impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> { if self.v.len() == 0 { (0, Some(0)) } else { - let (n, rem) = self.v.len().div_rem(&self.size); + let (n, rem) = div_rem(self.v.len(), self.size); let n = if rem > 0 { n+1 } else { n }; (n, Some(n)) } @@ -2859,7 +2859,7 @@ impl<'a, T> Iterator<&'a mut [T]> for MutChunks<'a, T> { if self.v.len() == 0 { (0, Some(0)) } else { - let (n, rem) = self.v.len().div_rem(&self.chunk_size); + let (n, rem) = div_rem(self.v.len(), self.chunk_size); let n = if rem > 0 { n + 1 } else { n }; (n, Some(n)) } diff --git a/src/test/bench/shootout-pidigits.rs b/src/test/bench/shootout-pidigits.rs index 93ef2b7bb8251..71cd176a836ff 100644 --- a/src/test/bench/shootout-pidigits.rs +++ b/src/test/bench/shootout-pidigits.rs @@ -14,6 +14,7 @@ use std::from_str::FromStr; use std::num::One; use std::num::Zero; use std::num::FromPrimitive; +use num::Integer; use num::bigint::BigInt; struct Context {