From 5ce0795de51b5305bcb48e69a5fcf8cb2e169a30 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Tue, 14 May 2013 18:14:45 +0900 Subject: [PATCH 1/5] libstd: impl Num for BigUint/BigInt --- src/libstd/num/bigint.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index 498c86dd8e101..53054afb4d2d8 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -144,6 +144,8 @@ impl FromStr for BigUint { } } +impl Num for BigUint {} + impl Shl for BigUint { #[inline(always)] fn shl(&self, rhs: &uint) -> BigUint { @@ -788,6 +790,8 @@ impl FromStr for BigInt { } } +impl Num for BigInt {} + impl Shl for BigInt { #[inline(always)] fn shl(&self, rhs: &uint) -> BigInt { From e3695468b742ff307da3cf29684128ed0785ee03 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Tue, 14 May 2013 21:20:27 +0900 Subject: [PATCH 2/5] libstd: impl `Orderable` for `BigUint`/`BigInt` --- src/libstd/num/bigint.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index 53054afb4d2d8..c35415c53317c 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -17,7 +17,7 @@ A BigInt is a combination of BigUint and Sign. */ use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; -use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix}; +use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable}; /** A BigDigit is a BigUint's composing element. @@ -146,6 +146,24 @@ impl FromStr for BigUint { impl Num for BigUint {} +impl Orderable for BigUint { + #[inline(always)] + fn min(&self, other: &BigUint) -> BigUint { + if self < other { self.clone() } else { other.clone() } + } + + #[inline(always)] + fn max(&self, other: &BigUint) -> BigUint { + if self > other { self.clone() } else { other.clone() } + } + + #[inline(always)] + fn clamp(&self, mn: &BigUint, mx: &BigUint) -> BigUint { + if self > mx { mx.clone() } else + if self < mn { mn.clone() } else { self.clone() } + } +} + impl Shl for BigUint { #[inline(always)] fn shl(&self, rhs: &uint) -> BigUint { @@ -792,6 +810,24 @@ impl FromStr for BigInt { impl Num for BigInt {} +impl Orderable for BigInt { + #[inline(always)] + fn min(&self, other: &BigInt) -> BigInt { + if self < other { self.clone() } else { other.clone() } + } + + #[inline(always)] + fn max(&self, other: &BigInt) -> BigInt { + if self > other { self.clone() } else { other.clone() } + } + + #[inline(always)] + fn clamp(&self, mn: &BigInt, mx: &BigInt) -> BigInt { + if self > mx { mx.clone() } else + if self < mn { mn.clone() } else { self.clone() } + } +} + impl Shl for BigInt { #[inline(always)] fn shl(&self, rhs: &uint) -> BigInt { From 41eaa97372ef0ede1f9f2657d2c6752bbf191edb Mon Sep 17 00:00:00 2001 From: gifnksm Date: Tue, 14 May 2013 21:25:53 +0900 Subject: [PATCH 3/5] libstd: `Rational` requires `Integer` as type bounds instead of `Num` --- src/libstd/num/rational.rs | 67 ++++++++------------------------------ 1 file changed, 14 insertions(+), 53 deletions(-) diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index 9b92b7241b990..c959629198195 100644 --- a/src/libstd/num/rational.rs +++ b/src/libstd/num/rational.rs @@ -30,7 +30,7 @@ pub type Rational64 = Ratio; /// Alias for arbitrary precision rationals. pub type BigRational = Ratio; -impl +impl Ratio { /// Create a ratio representing the integer `t`. #[inline(always)] @@ -57,7 +57,7 @@ impl /// Put self into lowest terms, with denom > 0. fn reduce(&mut self) { - let g : T = gcd(self.numer, self.denom); + let g : T = self.numer.gcd(&self.denom); self.numer /= g; self.denom /= g; @@ -76,34 +76,6 @@ impl } } -/** -Compute the greatest common divisor of two numbers, via Euclid's algorithm. - -The result can be negative. -*/ -#[inline] -pub fn gcd_raw(n: T, m: T) -> T { - let mut m = m, n = n; - while m != Zero::zero() { - let temp = m; - m = n % temp; - n = temp; - } - n -} - -/** -Compute the greatest common divisor of two numbers, via Euclid's algorithm. - -The result is always positive. -*/ -#[inline] -pub fn gcd(n: T, m: T) -> T { - let g = gcd_raw(n, m); - if g < Zero::zero() { -g } - else { g } -} - /* Comparisons */ // comparing a/b and c/d is the same as comparing a*d and b*c, so we @@ -133,7 +105,7 @@ cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering) /* Arithmetic */ // a/b * c/d = (a*c)/(b*d) -impl +impl Mul,Ratio> for Ratio { #[inline] fn mul(&self, rhs: &Ratio) -> Ratio { @@ -142,7 +114,7 @@ impl } // (a/b) / (c/d) = (a*d)/(b*c) -impl +impl Div,Ratio> for Ratio { #[inline] fn div(&self, rhs: &Ratio) -> Ratio { @@ -153,7 +125,7 @@ impl // Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern macro_rules! arith_impl { (impl $imp:ident, $method:ident) => { - impl + impl $imp,Ratio> for Ratio { #[inline] fn $method(&self, rhs: &Ratio) -> Ratio { @@ -173,16 +145,16 @@ arith_impl!(impl Sub, sub) // a/b % c/d = (a*d % b*c)/(b*d) arith_impl!(impl Rem, rem) -impl +impl Neg> for Ratio { #[inline] fn neg(&self) -> Ratio { - Ratio::new_raw(-self.numer, self.denom) + Ratio::new_raw(-self.numer, self.denom.clone()) } } /* Constants */ -impl +impl Zero for Ratio { #[inline] fn zero() -> Ratio { @@ -195,7 +167,7 @@ impl } } -impl +impl One for Ratio { #[inline] fn one() -> Ratio { @@ -203,11 +175,11 @@ impl } } -impl +impl Num for Ratio {} /* Utils */ -impl +impl Round for Ratio { fn floor(&self) -> Ratio { @@ -245,7 +217,7 @@ impl } } -impl Fractional for Ratio { +impl Fractional for Ratio { #[inline] fn recip(&self) -> Ratio { Ratio::new_raw(self.denom, self.numer) @@ -266,7 +238,7 @@ impl ToStrRadix for Ratio { } } -impl +impl FromStr for Ratio { /// Parses `numer/denom`. fn from_str(s: &str) -> Option> { @@ -283,7 +255,7 @@ impl } } } -impl +impl FromStrRadix for Ratio { /// Parses `numer/denom` where the numbers are in base `radix`. fn from_str_radix(s: &str, radix: uint) -> Option> { @@ -316,17 +288,6 @@ mod test { pub static _3_2: Rational = Ratio { numer: 3, denom: 2}; pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2}; - #[test] - fn test_gcd() { - assert_eq!(gcd(10,2),2); - assert_eq!(gcd(10,3),1); - assert_eq!(gcd(0,3),3); - assert_eq!(gcd(3,3),3); - - assert_eq!(gcd(3,-3), 3); - assert_eq!(gcd(-6,3), 3); - assert_eq!(gcd(-4,-2), 2); - } #[test] fn test_test_constants() { From 76ecce0e0c1e307d0c387b3cc219d8410fe7a6f6 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Tue, 14 May 2013 21:31:43 +0900 Subject: [PATCH 4/5] libstd: `Ratio` requires `Clone` instead of `Copy` This allows creating `Ratio` which `T` is non-implicitly copyable types such as `BigInt`. --- src/libstd/num/rational.rs | 51 +++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index c959629198195..0ec6f7457d6e4 100644 --- a/src/libstd/num/rational.rs +++ b/src/libstd/num/rational.rs @@ -30,7 +30,7 @@ pub type Rational64 = Ratio; /// Alias for arbitrary precision rationals. pub type BigRational = Ratio; -impl +impl Ratio { /// Create a ratio representing the integer `t`. #[inline(always)] @@ -59,8 +59,12 @@ impl fn reduce(&mut self) { let g : T = self.numer.gcd(&self.denom); - self.numer /= g; - self.denom /= g; + // FIXME(#6050): overloaded operators force moves with generic types + // self.numer /= g; + self.numer = self.numer / g; + // FIXME(#6050): overloaded operators force moves with generic types + // self.denom /= g; + self.denom = self.denom / g; // keep denom positive! if self.denom < Zero::zero() { @@ -68,9 +72,10 @@ impl self.denom = -self.denom; } } + /// Return a `reduce`d copy of self. fn reduced(&self) -> Ratio { - let mut ret = copy *self; + let mut ret = self.clone(); ret.reduce(); ret } @@ -105,7 +110,7 @@ cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering) /* Arithmetic */ // a/b * c/d = (a*c)/(b*d) -impl +impl Mul,Ratio> for Ratio { #[inline] fn mul(&self, rhs: &Ratio) -> Ratio { @@ -114,7 +119,7 @@ impl } // (a/b) / (c/d) = (a*d)/(b*c) -impl +impl Div,Ratio> for Ratio { #[inline] fn div(&self, rhs: &Ratio) -> Ratio { @@ -125,7 +130,7 @@ impl // Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern macro_rules! arith_impl { (impl $imp:ident, $method:ident) => { - impl + impl $imp,Ratio> for Ratio { #[inline] fn $method(&self, rhs: &Ratio) -> Ratio { @@ -145,7 +150,7 @@ arith_impl!(impl Sub, sub) // a/b % c/d = (a*d % b*c)/(b*d) arith_impl!(impl Rem, rem) -impl +impl Neg> for Ratio { #[inline] fn neg(&self) -> Ratio { @@ -154,7 +159,7 @@ impl } /* Constants */ -impl +impl Zero for Ratio { #[inline] fn zero() -> Ratio { @@ -167,7 +172,7 @@ impl } } -impl +impl One for Ratio { #[inline] fn one() -> Ratio { @@ -175,11 +180,11 @@ impl } } -impl +impl Num for Ratio {} /* Utils */ -impl +impl Round for Ratio { fn floor(&self) -> Ratio { @@ -213,14 +218,14 @@ impl } fn fract(&self) -> Ratio { - Ratio::new_raw(self.numer % self.denom, self.denom) + Ratio::new_raw(self.numer % self.denom, self.denom.clone()) } } -impl Fractional for Ratio { +impl Fractional for Ratio { #[inline] fn recip(&self) -> Ratio { - Ratio::new_raw(self.denom, self.numer) + Ratio::new_raw(self.denom.clone(), self.numer.clone()) } } @@ -238,7 +243,7 @@ impl ToStrRadix for Ratio { } } -impl +impl FromStr for Ratio { /// Parses `numer/denom`. fn from_str(s: &str) -> Option> { @@ -248,14 +253,14 @@ impl } }); if split.len() < 2 { return None; } - do FromStr::from_str(split[0]).chain |a| { - do FromStr::from_str(split[1]).chain |b| { - Some(Ratio::new(a,b)) + do FromStr::from_str::(split[0]).chain |a| { + do FromStr::from_str::(split[1]).chain |b| { + Some(Ratio::new(a.clone(), b.clone())) } } } } -impl +impl FromStrRadix for Ratio { /// Parses `numer/denom` where the numbers are in base `radix`. fn from_str_radix(s: &str, radix: uint) -> Option> { @@ -266,9 +271,9 @@ impl }); if split.len() < 2 { None } else { - do FromStrRadix::from_str_radix(split[0], radix).chain |a| { - do FromStrRadix::from_str_radix(split[1], radix).chain |b| { - Some(Ratio::new(a,b)) + do FromStrRadix::from_str_radix::(split[0], radix).chain |a| { + do FromStrRadix::from_str_radix::(split[1], radix).chain |b| { + Some(Ratio::new(a.clone(), b.clone())) } } } From da9c1fbf2740258fcb73a3d23bf3cf9d7d096189 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Tue, 14 May 2013 21:33:39 +0900 Subject: [PATCH 5/5] libstd: Add tests for BigRational --- src/libstd/num/rational.rs | 76 ++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index 0ec6f7457d6e4..0f1b754490db8 100644 --- a/src/libstd/num/rational.rs +++ b/src/libstd/num/rational.rs @@ -283,7 +283,7 @@ impl #[cfg(test)] mod test { use super::*; - use core::num::{Zero,One,FromStrRadix}; + use core::num::{Zero,One,FromStrRadix,IntConvertible}; use core::from_str::FromStr; pub static _0 : Rational = Ratio { numer: 0, denom: 1}; @@ -293,6 +293,12 @@ mod test { pub static _3_2: Rational = Ratio { numer: 3, denom: 2}; pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2}; + pub fn to_big(n: Rational) -> BigRational { + Ratio::new( + IntConvertible::from_int(n.numer), + IntConvertible::from_int(n.denom) + ) + } #[test] fn test_test_constants() { @@ -340,45 +346,75 @@ mod test { #[test] fn test_add() { - assert_eq!(_1 + _1_2, _3_2); - assert_eq!(_1 + _1, _2); - assert_eq!(_1_2 + _3_2, _2); - assert_eq!(_1_2 + _neg1_2, _0); + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a + b, c); + assert_eq!(to_big(a) + to_big(b), to_big(c)); + } + + test(_1, _1_2, _3_2); + test(_1, _1, _2); + test(_1_2, _3_2, _2); + test(_1_2, _neg1_2, _0); } #[test] fn test_sub() { - assert_eq!(_1 - _1_2, _1_2); - assert_eq!(_3_2 - _1_2, _1); - assert_eq!(_1 - _neg1_2, _3_2); + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a - b, c); + assert_eq!(to_big(a) - to_big(b), to_big(c)) + } + + test(_1, _1_2, _1_2); + test(_3_2, _1_2, _1); + test(_1, _neg1_2, _3_2); } #[test] fn test_mul() { - assert_eq!(_1 * _1_2, _1_2); - assert_eq!(_1_2 * _3_2, Ratio::new(3,4)); - assert_eq!(_1_2 * _neg1_2, Ratio::new(-1, 4)); + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a * b, c); + assert_eq!(to_big(a) * to_big(b), to_big(c)) + } + + test(_1, _1_2, _1_2); + test(_1_2, _3_2, Ratio::new(3,4)); + test(_1_2, _neg1_2, Ratio::new(-1, 4)); } #[test] fn test_div() { - assert_eq!(_1 / _1_2, _2); - assert_eq!(_3_2 / _1_2, _1 + _2); - assert_eq!(_1 / _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2); + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a / b, c); + assert_eq!(to_big(a) / to_big(b), to_big(c)) + } + + test(_1, _1_2, _2); + test(_3_2, _1_2, _1 + _2); + test(_1, _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2); } #[test] fn test_rem() { - assert_eq!(_3_2 % _1, _1_2); - assert_eq!(_2 % _neg1_2, _0); - assert_eq!(_1_2 % _2, _1_2); + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a % b, c); + assert_eq!(to_big(a) % to_big(b), to_big(c)) + } + + test(_3_2, _1, _1_2); + test(_2, _neg1_2, _0); + test(_1_2, _2, _1_2); } #[test] fn test_neg() { - assert_eq!(-_0, _0); - assert_eq!(-_1_2, _neg1_2); - assert_eq!(-(-_1), _1); + fn test(a: Rational, b: Rational) { + assert_eq!(-a, b); + assert_eq!(-to_big(a), to_big(b)) + } + + test(_0, _0); + test(_1_2, _neg1_2); + test(-_1, _1); } #[test] fn test_zero() {