1use num::{Float, NumCast, integer::gcd};
2
3use super::*;
4
5#[derive(Clone, Copy)]
6pub struct Rational {
7 pub num: isize,
8 pub denom: isize,
9}
10
11impl Expr for Rational {
12 fn known_expr(&self) -> KnownExpr {
13 KnownExpr::Rational(self)
14 }
15 fn for_each_arg(&self, f: &mut dyn FnMut(&dyn Arg) -> ()) {
16 f(&self.num);
17 f(&self.denom);
18 }
19
20 fn from_args(&self, args: Vec<Box<dyn Arg>>) -> Box<dyn Expr> {
21 Box::new(Rational {
22 num: *args[0].as_any().downcast_ref::<isize>().unwrap(),
23 denom: *args[1].as_any().downcast_ref::<isize>().unwrap(),
24 })
25 }
26
27 fn clone_box(&self) -> Box<dyn Expr> {
28 Box::new(self.clone())
29 }
30
31 fn str(&self) -> String {
32 format!("{}/{}", self.num, self.denom)
33 }
34
35 fn to_cpp(&self) -> String {
36 format!("{}./{}.", self.num, self.denom)
37 }
38
39 fn get_ref<'a>(&'a self) -> &'a dyn Expr {
40 self as &dyn Expr
41 }
42
43 fn is_one(&self) -> bool {
44 self.num == self.denom
45 }
46
47 fn is_zero(&self) -> bool {
48 self.num == 0
49 }
50
51 fn is_neg_one(&self) -> bool {
52 self.num == -self.denom
53 }
54 fn is_number(&self) -> bool {
55 true
56 }
57
58 fn is_negative_number(&self) -> bool {
59 self.num * self.denom < 0
60 }
61
62 fn as_f64(&self) -> Option<f64> {
63 Some(self.num.to_f64().unwrap() / self.denom.to_f64().unwrap())
64 }
65 fn simplify(&self) -> Box<dyn Expr> {
66 let mut res = self.clone();
67 if self.num < 0 && self.denom < 0 {
68 res.num *= -1;
69 res.denom *= -1;
70 }
71 let d = gcd(self.num, self.denom);
72 res.num /= d;
73 res.denom /= d;
74 if self.num % self.denom == 0 {
75 Integer::new_box(self.num / self.denom)
76 } else {
77 Box::new(res)
78 }
79 }
80}
81
82impl Rational {
83 pub fn new(num: isize, denom: isize) -> Self {
84 Rational { num, denom }
85 }
86
87 pub fn new_box(num: isize, denom: isize) -> Box<dyn Expr> {
88 Box::new(Rational { num, denom })
89 }
90 pub fn one() -> Self {
91 Rational { num: 1, denom: 1 }
92 }
93
94 pub fn zero() -> Self {
95 Rational { num: 0, denom: 1 }
96 }
97
98 pub fn invert(&mut self) {
99 std::mem::swap(&mut self.num, &mut self.denom);
100 }
101}
102
103impl std::fmt::Debug for Rational {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "{}", self.srepr())
111 }
112}
113
114pub trait ToInteger {
115 fn to_integer(&self) -> Integer;
116}
117
118impl ToInteger for i32 {
119 fn to_integer(&self) -> Integer {
120 Integer::new(*self as isize)
121 }
122}
123
124impl<N: ToInteger> From<N> for Rational {
125 fn from(value: N) -> Self {
126 Rational {
127 num: value.to_integer().value,
128 denom: 1,
129 }
130 }
131}
132
133impl Rational {
143 pub fn from_float<N: Float + ToString>(value: N) -> Rational {
144 let srepr = value.to_string();
145 let decimals = srepr.split('.').last().unwrap_or("");
146 let num_decimals = decimals.len();
147
148 let mut rational = Rational {
149 num: srepr.replace(".", "").parse().expect("valid integer"),
150 denom: (10 as isize).pow(num_decimals as u32),
151 };
152
153 let gcd = gcd(rational.num, rational.denom);
154 rational.num /= gcd;
155 rational.denom /= gcd;
156
157 rational
158 }
159}
160
161impl<I: ToPrimitive> std::ops::Mul<I> for Rational {
162 type Output = Rational;
163
164 fn mul(self, rhs: I) -> Self::Output {
165 Rational {
166 num: self.num * rhs.to_isize().unwrap(),
167 denom: self.denom,
168 }
169 }
170}
171
172impl<T: Copy + Into<Rational>> PartialEq<T> for Rational {
175 fn eq(&self, other: &T) -> bool {
176 let other: Rational = (*other).into();
177 self.num * other.denom == self.denom * other.num
178 }
179}
180
181impl std::cmp::Eq for Rational {}
182
183impl<T: Copy + Into<Rational>> PartialOrd<T> for Rational {
193 fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
194 let a: f64 = self.into();
195 let b: Rational = (*other).into();
196 let b: f64 = b.into();
197
198 a.partial_cmp(&b)
199 }
200}
201
202impl Ord for Rational {
203 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
204 let a: f64 = self.into();
205 let b: f64 = other.into();
206 a.partial_cmp(&b).unwrap()
207 }
208}
209
210impl From<&Rational> for f64 {
211 fn from(Rational { num, denom }: &Rational) -> Self {
212 *num as f64 / *denom as f64
213 }
214}
215
216impl From<Rational> for f64 {
217 fn from(Rational { num, denom }: Rational) -> Self {
218 num as f64 / denom as f64
219 }
220}
221
222impl std::ops::Add for &Rational {
223 type Output = Rational;
224
225 fn add(self, rhs: Self) -> Self::Output {
226 Rational {
227 num: self.num * rhs.denom + rhs.num * self.denom,
228 denom: self.denom * rhs.denom,
229 }
230 }
231}
232
233impl std::ops::Add for Rational {
234 type Output = Rational;
235
236 fn add(self, rhs: Self) -> Self::Output {
237 Rational {
238 num: self.num * rhs.denom + rhs.num * self.denom,
239 denom: self.denom * rhs.denom,
240 }
241 }
242}
243
244impl std::ops::AddAssign for Rational {
245 fn add_assign(&mut self, rhs: Self) {
246 let res = *self + rhs;
247
248 self.num = res.num;
249 self.denom = res.denom;
250 }
251}
252
253impl std::ops::Add<&Integer> for &Rational {
254 type Output = Box<dyn Expr>;
255
256 fn add(self, rhs: &Integer) -> Self::Output {
257 Rational::new_box(self.num + rhs.value * self.denom, self.denom).simplify()
258 }
259}
260
261impl std::ops::Add<&Rational> for &Integer {
262 type Output = Box<dyn Expr>;
263
264 fn add(self, rhs: &Rational) -> Self::Output {
265 Rational::new_box(self.value * rhs.denom + rhs.num, rhs.denom).simplify()
266 }
267}
268
269impl std::ops::Neg for &Rational {
270 type Output = Rational;
271
272 fn neg(self) -> Self::Output {
273 Rational {
274 num: -self.num,
275 denom: self.denom,
276 }
277 }
278}
279
280impl std::ops::Sub for Rational {
281 type Output = Rational;
282
283 fn sub(self, rhs: Rational) -> Self::Output {
284 Rational {
285 num: self.num * rhs.denom - rhs.num * self.denom,
286 denom: self.denom * rhs.denom,
287 }
288 }
289}
290
291impl<N: NumCast> std::ops::Sub<N> for Rational {
292 type Output = Box<dyn Expr>;
293
294 fn sub(self, rhs: N) -> Self::Output {
295 let rhs: Rational = rhs.to_i32().unwrap().into();
296
297 (self - rhs).simplify()
298 }
299}
300
301impl<I: ToPrimitive> std::ops::MulAssign<&I> for Rational {
302 fn mul_assign(&mut self, rhs: &I) {
303 self.num *= rhs.to_isize().unwrap();
304 }
305}
306
307impl std::ops::Mul<Rational> for Rational {
308 type Output = Rational;
309
310 fn mul(self, rhs: Rational) -> Self::Output {
311 Rational {
312 num: self.num * rhs.num,
313 denom: self.denom * rhs.denom,
314 }
315 }
316}
317
318impl std::ops::Div<Rational> for Rational {
319 type Output = Rational;
320
321 fn div(self, rhs: Rational) -> Self::Output {
322 Rational {
323 num: self.num * rhs.denom,
324 denom: self.denom * rhs.num,
325 }
326 }
327}
328
329impl std::ops::MulAssign<&Rational> for Rational {
330 fn mul_assign(&mut self, rhs: &Rational) {
331 self.num *= rhs.num;
332 self.denom *= rhs.denom;
333 }
334}
335
336impl std::ops::DivAssign<&Rational> for Rational {
337 fn div_assign(&mut self, rhs: &Rational) {
338 self.num *= rhs.denom;
339 self.denom *= rhs.num;
340 }
341}
342
343impl std::ops::DivAssign for Rational {
344 fn div_assign(&mut self, rhs: Rational) {
345 self.num *= rhs.denom;
346 self.denom *= rhs.num;
347 }
348}
349
350impl From<&str> for Rational {
351 fn from(value: &str) -> Self {
352 let (num, denom) = value.split_once('/').unwrap();
353 Rational {
354 num: num.parse().unwrap(),
355 denom: denom.parse().unwrap(),
356 }
357 }
358}
359
360#[cfg(test)]
361mod tests {
362
363 use super::*;
364
365 #[test]
366 fn test_mul_rational_int() {
367 let r = Rational::new(3, 4);
368 let i = 3;
369 let expected = Rational::new(3 * 3, 4);
370
371 assert_eq!(r * i, expected);
372 }
373
374 #[test]
375 fn test_simplify_basic() {
376 let expr = Rational::new(3, 4);
377 let expected = Rational::new_box(3, 4);
378 assert_eq!(&expr.simplify(), &expected)
379 }
380
381 #[test]
382 fn test_simpify_to_int() {
383 let expr = Rational::new(9, 3);
384 let expected = Integer::new_box(3);
385 assert_eq!(&expr.simplify(), &expected)
386 }
387
388 #[test]
389 fn test_add() {
390 assert_eq!(
391 Rational::new(3, 4) + Rational::new(2, 5),
392 Rational::new(23, 20)
393 )
394 }
395
396 #[test]
397 fn test_ord() {
398 let [a, b] = [Rational::from("1/2"), Rational::from("1/3")];
399
400 assert!(a > b)
401 }
402
403 #[test]
404 fn test_add_bis() {
405 assert_eq!(
406 Rational::new(1, 4) + Rational::new(-1, 2),
407 Rational::new(-1, 4)
408 )
409 }
410}