From 1aabce4f605cbb08e93f589c507afbad403c8bae Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Fri, 7 Sep 2018 08:14:33 -0700 Subject: [PATCH] [types] Add GCD and LCM to Int; implement Rem on Int --- types/src/number/arith.rs | 37 +++++++++++++++ types/src/number/frac.rs | 1 + types/src/number/integer.rs | 78 +++++++++++++++++++++++++++++- types/src/number/math.rs | 95 ------------------------------------- types/src/number/mod.rs | 1 + 5 files changed, 116 insertions(+), 96 deletions(-) create mode 100644 types/src/number/arith.rs delete mode 100644 types/src/number/math.rs diff --git a/types/src/number/arith.rs b/types/src/number/arith.rs new file mode 100644 index 0000000..69740b5 --- /dev/null +++ b/types/src/number/arith.rs @@ -0,0 +1,37 @@ +/* types/src/number/arith.rs + * Eryn Wells + */ + +pub trait GCD { + /// Find the greatest common divisor of `self` and another number. + fn gcd(self, other: Self) -> Self; +} + +pub trait LCM { + /// Find the least common multiple of `self` and another number. + fn lcm(self, other: Self) -> Self; +} + +//impl Rational for Int { +// fn to_rational(self) -> (Int, Int) { (self, 1) } +//} +// +//impl Rational for Flt { +// fn to_rational(self) -> (Int, Int) { +// // Convert the float to a fraction by iteratively multiplying by 10 until the fractional part of the float is 0.0. +// let whole_part = self.trunc(); +// let mut p = self.fract(); +// let mut q = 1.0; +// while p.fract() != 0.0 { +// p *= 10.0; +// q *= 10.0; +// } +// p += whole_part * q; +// +// // Integers from here down. Reduce the fraction before returning. +// let p = p as Int; +// let q = q as Int; +// let gcd = p.gcd(q); +// (p / gcd, q / gcd) +// } +//} diff --git a/types/src/number/frac.rs b/types/src/number/frac.rs index a22df8e..b175e79 100644 --- a/types/src/number/frac.rs +++ b/types/src/number/frac.rs @@ -4,6 +4,7 @@ use std::any::Any; use std::fmt; +use std::ops::{Add, Mul}; use number::{Int, Number}; use object::{Obj, Object}; diff --git a/types/src/number/integer.rs b/types/src/number/integer.rs index 35b87fb..98ff532 100644 --- a/types/src/number/integer.rs +++ b/types/src/number/integer.rs @@ -4,7 +4,8 @@ use std::any::Any; use std::fmt; -use std::ops::{Add, Mul}; +use std::ops::{Add, Mul, Rem}; +use number::arith::{GCD, LCM}; use number::{Frac, Number}; use object::{Obj, Object}; @@ -38,6 +39,32 @@ impl fmt::Display for Int { } } +impl GCD for Int { + fn gcd(self, other: Int) -> Int { + let (mut a, mut b) = if self.0 > other.0 { + (self.0, other.0) + } else { + (other.0, self.0) + }; + while b != 0 { + let r = a % b; + a = b; + b = r; + } + Int(a) + } +} + +impl LCM for Int { + fn lcm(self, other: Int) -> Int { + if self.0 == 0 && other.0 == 0 { + Int(0) + } else { + Int(self.0 * other.0 / self.gcd(other).0) + } + } +} + impl Object for Int { fn as_any(&self) -> &Any { self } fn as_num(&self) -> Option<&Number> { Some(self) } @@ -87,6 +114,27 @@ impl<'a> PartialEq for Int { } } +impl Rem for Int { + type Output = Int; + fn rem(self, rhs: Self) -> Self::Output { + Int(self.0 % rhs.0) + } +} + +impl<'a> Rem for &'a Int { + type Output = Int; + fn rem(self, rhs: Int) -> Self::Output { + Int(self.0 % rhs.0) + } +} + +impl<'a, 'b> Rem<&'a Int> for &'b Int { + type Output = Int; + fn rem(self, rhs: &Int) -> Self::Output { + Int(self.0 % rhs.0) + } +} + #[cfg(test)] mod tests { use super::*; @@ -113,4 +161,32 @@ mod tests { fn integers_add() { assert_eq!(Int(4) + Int(8), Int(12)); } + + #[test] + fn integers_multiply() { + assert_eq!(Int(4) * Int(5), Int(20)); + } + + #[test] + fn integer_modulo_divide() { + assert_eq!(Int(20) % Int(5), Int(0)); + assert_eq!(Int(20) % Int(6), Int(2)); + } + + #[test] + fn finding_int_gcd() { + assert_eq!(Int(0), Int(0).gcd(Int(0))); + assert_eq!(Int(10), Int(10).gcd(Int(0))); + assert_eq!(Int(10), Int(0).gcd(Int(10))); + assert_eq!(Int(10), Int(10).gcd(Int(20))); + assert_eq!(Int(44), Int(2024).gcd(Int(748))); + } + + #[test] + fn finding_int_lcm() { + assert_eq!(Int(0), Int(0).lcm(Int(0))); + assert_eq!(Int(0), Int(10).lcm(Int(0))); + assert_eq!(Int(0), Int(10).lcm(Int(0))); + assert_eq!(Int(42), Int(21).lcm(Int(6))); + } } diff --git a/types/src/number/math.rs b/types/src/number/math.rs deleted file mode 100644 index a5ef5b7..0000000 --- a/types/src/number/math.rs +++ /dev/null @@ -1,95 +0,0 @@ -/* types/src/number/math.rs - * Eryn Wells - */ - -use number::{Int, Flt}; - -pub trait GCD { - /// Find the greatest common divisor of `self` and another number. - fn gcd(self, other: Self) -> Self; -} - -pub trait LCM { - /// Find the least common multiple of `self` and another number. - fn lcm(self, other: Self) -> Self; -} - -pub trait Rational { - /// Convert `self` into a rational number -- the quotient of two whole numbers. - fn to_rational(self) -> (Int, Int); -} - -impl GCD for Int { - fn gcd(self, other: Int) -> Int { - let (mut a, mut b) = if self > other { - (self, other) - } else { - (other, self) - }; - - while b != 0 { - let r = a % b; - a = b; - b = r; - } - - a - } -} - -impl LCM for Int { - fn lcm(self, other: Int) -> Int { - if self == 0 && other == 0 { - 0 - } - else { - self * other / self.gcd(other) - } - } -} - -impl Rational for Int { - fn to_rational(self) -> (Int, Int) { (self, 1) } -} - -impl Rational for Flt { - fn to_rational(self) -> (Int, Int) { - // Convert the float to a fraction by iteratively multiplying by 10 until the fractional part of the float is 0.0. - let whole_part = self.trunc(); - let mut p = self.fract(); - let mut q = 1.0; - while p.fract() != 0.0 { - p *= 10.0; - q *= 10.0; - } - p += whole_part * q; - - // Integers from here down. Reduce the fraction before returning. - let p = p as Int; - let q = q as Int; - let gcd = p.gcd(q); - (p / gcd, q / gcd) - } -} - -#[cfg(test)] -mod tests { - use super::{LCM, GCD}; - - #[test] - fn gcd_works() { - assert_eq!(0, 0.gcd(0)); - assert_eq!(10, 10.gcd(0)); - assert_eq!(10, 0.gcd(10)); - assert_eq!(10, 10.gcd(20)); - assert_eq!(44, 2024.gcd(748)); - } - - #[test] - fn lcm_works() { - assert_eq!(0, 0.lcm(0)); - assert_eq!(0, 10.lcm(0)); - assert_eq!(0, 10.lcm(0)); - assert_eq!(42, 21.lcm(6)); - } -} diff --git a/types/src/number/mod.rs b/types/src/number/mod.rs index ae775bc..f34cd8a 100644 --- a/types/src/number/mod.rs +++ b/types/src/number/mod.rs @@ -11,6 +11,7 @@ //! Integer can be cast as a Rational (by putting its value over 1), but a Rational like 1/2 cannot //! be represented as an Integer. +mod arith; mod integer; mod frac;