[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