[types] More operations on Ints and some tests for Frac
Implement Div on Int Make sure Fracs are reduced when they are produced, plus some error handling if you create a x/0 Frac
This commit is contained in:
		
							parent
							
								
									1aabce4f60
								
							
						
					
					
						commit
						a5ed11ea77
					
				
					 2 changed files with 48 additions and 15 deletions
				
			
		|  | @ -5,28 +5,40 @@ | |||
| use std::any::Any; | ||||
| use std::fmt; | ||||
| use std::ops::{Add, Mul}; | ||||
| use number::arith::GCD; | ||||
| use number::{Int, Number}; | ||||
| use object::{Obj, Object}; | ||||
| 
 | ||||
| /// A fraction consisting of a numerator and denominator.
 | ||||
| #[derive(Debug, Eq, PartialEq)] | ||||
| pub struct Frac(pub i64, pub u64); | ||||
| #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] | ||||
| pub struct Frac(Int, Int); | ||||
| 
 | ||||
| impl Frac { | ||||
|     pub fn new(p: Int, q: Int) -> Result<Frac, ()> { | ||||
|         if q == Int(0) { | ||||
|             // TODO: Return a more specific error about dividing by zero.
 | ||||
|             Err(()) | ||||
|         } else { | ||||
|             Ok(Frac(p, q).reduced()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn reduced(self) -> Frac { | ||||
|         let gcd = self.0.gcd(self.1); | ||||
|         Frac(self.0 / gcd, self.1 / gcd) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Number for Frac { | ||||
|     fn as_int(&self) -> Option<Int> { | ||||
|         if self.1 == 1 { | ||||
|             Some(Int(self.0)) | ||||
|         if self.1 == Int(1) { | ||||
|             Some(self.0) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn as_frac(&self) -> Option<Frac> { | ||||
|         Some(Frac(self.0, self.1)) | ||||
|     } | ||||
|     fn as_frac(&self) -> Option<Frac> { Frac::new(self.0, self.1).ok() } | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for Frac { | ||||
|  | @ -64,25 +76,25 @@ mod tests { | |||
| 
 | ||||
|     #[test] | ||||
|     fn equal_fracs_are_equal() { | ||||
|         assert_eq!(Frac(3, 2), Frac(3, 2)); | ||||
|         assert_ne!(Frac(12, 4), Frac(9, 7)); | ||||
|         assert_eq!(Frac(Int(3), Int(2)), Frac(Int(3), Int(2))); | ||||
|         assert_ne!(Frac(Int(12), Int(4)), Frac(Int(9), Int(7))); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn fracs_should_reduce_to_ints_where_possible() { | ||||
|         let rational_as_integer = Frac(3, 1).as_int(); | ||||
|         let rational_as_integer = Frac(Int(3), Int(1)).as_int(); | ||||
|         assert!(rational_as_integer.is_some()); | ||||
|         // Oh my god this line is so dumb.
 | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn fracs_should_not_reduce_to_ints_where_impossible() { | ||||
|         let rational_as_integer = Frac(3, 2).as_int(); | ||||
|         let rational_as_integer = Frac(Int(3), Int(2)).as_int(); | ||||
|         assert!(rational_as_integer.is_none()); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn fracs_are_exact() { | ||||
|         assert!(Frac(4, 2).is_exact()); | ||||
|         assert!(Frac(Int(4), Int(2)).is_exact()); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -4,12 +4,12 @@ | |||
| 
 | ||||
| use std::any::Any; | ||||
| use std::fmt; | ||||
| use std::ops::{Add, Mul, Rem}; | ||||
| use std::ops::{Add, Div, Mul, Rem}; | ||||
| use number::arith::{GCD, LCM}; | ||||
| use number::{Frac, Number}; | ||||
| use object::{Obj, Object}; | ||||
| 
 | ||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||||
| #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] | ||||
| pub struct Int(pub i64); | ||||
| 
 | ||||
| impl Add for Int { | ||||
|  | @ -39,6 +39,27 @@ impl fmt::Display for Int { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Div for Int { | ||||
|     type Output = Int; | ||||
|     fn div(self, rhs: Self) -> Self::Output { | ||||
|         Int(self.0 / rhs.0) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a> Div<Int> for &'a Int { | ||||
|     type Output = Int; | ||||
|     fn div(self, rhs: Int) -> Self::Output { | ||||
|         Int(self.0 / rhs.0) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'b> Div<&'a Int> for &'b Int { | ||||
|     type Output = Int; | ||||
|     fn div(self, rhs: &Int) -> Self::Output { | ||||
|         Int(self.0 / rhs.0) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl GCD for Int { | ||||
|     fn gcd(self, other: Int) -> Int { | ||||
| 		let (mut a, mut b) = if self.0 > other.0 { | ||||
|  | @ -72,7 +93,7 @@ impl Object for Int { | |||
| 
 | ||||
| impl Number for Int { | ||||
|     fn as_int(&self) -> Option<Int> { Some(*self) } | ||||
|     fn as_frac(&self) -> Option<Frac> { Some(Frac(self.0, 1)) } | ||||
|     fn as_frac(&self) -> Option<Frac> { Frac::new(*self, Int(1)).ok() } | ||||
| } | ||||
| 
 | ||||
| impl Mul for Int { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue