[types] Add GCD and LCM to Int; implement Rem on Int
This commit is contained in:
		
							parent
							
								
									45bc366a41
								
							
						
					
					
						commit
						1aabce4f60
					
				
					 5 changed files with 116 additions and 96 deletions
				
			
		
							
								
								
									
										37
									
								
								types/src/number/arith.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								types/src/number/arith.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| /* types/src/number/arith.rs
 | ||||
|  * Eryn Wells <eryn@erynwells.me> | ||||
|  */ | ||||
| 
 | ||||
| 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)
 | ||||
| //    }
 | ||||
| //}
 | ||||
|  | @ -4,6 +4,7 @@ | |||
| 
 | ||||
| use std::any::Any; | ||||
| use std::fmt; | ||||
| use std::ops::{Add, Mul}; | ||||
| use number::{Int, Number}; | ||||
| use object::{Obj, Object}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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<Number + 'a> for Int { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Rem for Int { | ||||
|     type Output = Int; | ||||
|     fn rem(self, rhs: Self) -> Self::Output { | ||||
|         Int(self.0 % rhs.0) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a> Rem<Int> 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))); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,95 +0,0 @@ | |||
| /* types/src/number/math.rs
 | ||||
|  * Eryn Wells <eryn@erynwells.me> | ||||
|  */ | ||||
| 
 | ||||
| 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)); | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue