1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::cmp::Ordering;
#[derive(Debug, Clone)]
pub struct Rational {
pub num: i64,
pub den: i64,
}
impl Rational {
pub fn new(num: i64, den: i64) -> Rational {
Rational {
num,
den,
}
}
pub fn zero() -> Rational { Rational::new(0, 1) }
pub fn unit() -> Rational { Rational::new(1, 1) }
pub fn trunc(&self) -> Rational {
Rational::from(self.num / self.den)
}
pub fn fract(&self) -> Rational {
Rational::new(
self.num % self.den,
self.den,
)
}
pub fn is_positive(&self) -> bool { (self.num > 0 && self.den > 0) || (self.num < 0 && self.den < 0) }
pub fn is_negative(&self) -> bool { (self.num < 0 && self.den > 0) || (self.num > 0 && self.den < 0) }
}
impl PartialEq for Rational {
fn eq(&self, other: &Rational) -> bool { self.cmp(other) == Ordering::Equal }
}
impl Eq for Rational {}
impl PartialOrd for Rational {
fn partial_cmp(&self, other: &Rational) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl Ord for Rational {
fn cmp(
&self,
other: &Rational,
) -> Ordering {
let (lhs_int, rhs_int) = (self.num / self.den, other.num / other.den);
let (lhs_rem, rhs_rem) = (self.num % self.den, other.num % other.den);
let int_cmp = lhs_int.cmp(&rhs_int);
if int_cmp != Ordering::Equal {
int_cmp
} else {
match (lhs_rem != 0, rhs_rem != 0) {
(false, false) => {
Ordering::Equal
}
(false, true) => {
Ordering::Less
}
(true, false) => {
Ordering::Greater
}
(true, true) => {
let lhs_recip = Rational::new(self.den, lhs_rem);
let rhs_recip = Rational::new(other.den, rhs_rem);
lhs_recip.cmp(&rhs_recip).reverse()
}
}
}
}
}
impl From<i64> for Rational {
fn from(n: i64) -> Self { Rational { num: n, den: 1 } }
}