1use std::{
9 cmp::Ordering,
10 fmt::{Debug, Display},
11 ops::{self, Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
12};
13
14use crate::expressions::{Atomic, IntegerExpression};
15
16#[derive(Debug, Clone, Copy, PartialEq, Hash)]
18pub struct Fraction {
19 negated: bool,
21 numerator: u32,
23 denominator: u32,
25}
26
27impl Display for Fraction {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 debug_assert!(self.is_simplified());
30
31 if let Ok(c) = i64::try_from(*self) {
32 write!(f, "{c}")
33 } else {
34 if self.negated {
35 write!(f, "-")?;
36 }
37 write!(f, "{}/{}", self.numerator, self.denominator)
38 }
39 }
40}
41
42impl Fraction {
43 pub fn is_negative(&self) -> bool {
59 debug_assert!(self.is_simplified());
60 self.negated
61 }
62
63 pub fn is_integer(&self) -> bool {
79 self.numerator.is_multiple_of(self.denominator)
80 }
81
82 fn is_simplified(&self) -> bool {
84 num::integer::gcd(self.numerator, self.denominator) == 1
85 }
86
87 pub fn new(numerator: u32, denominator: u32, negated: bool) -> Self {
105 Self {
106 negated,
107 numerator,
108 denominator,
109 }
110 .canonicalize()
111 }
112
113 fn canonicalize(self) -> Self {
115 if self.numerator == 0 {
117 return Self {
118 negated: false,
119 numerator: 0,
120 denominator: 1,
121 };
122 }
123
124 if self.denominator == 0 {
126 return Self {
127 negated: false,
128 numerator: 1,
129 denominator: 0,
130 };
131 }
132
133 let mut numerator = self.numerator;
135 let mut denominator = self.denominator;
136 let gcd = num::integer::gcd(self.numerator, self.denominator);
137
138 numerator /= gcd;
139 denominator /= gcd;
140
141 Self {
142 negated: self.negated,
143 numerator,
144 denominator,
145 }
146 }
147
148 pub fn inverse(&self) -> Self {
162 if self.numerator() == 0 {
163 panic!("Division by zero undefined!");
164 }
165
166 Self {
167 negated: self.negated,
168 numerator: self.denominator,
169 denominator: self.numerator,
170 }
171 }
172
173 pub fn denominator(&self) -> u32 {
184 debug_assert!(self.is_simplified());
185 self.denominator
186 }
187
188 pub fn numerator(&self) -> u32 {
199 debug_assert!(self.is_simplified());
200 self.numerator
201 }
202}
203
204impl ops::Neg for Fraction {
205 type Output = Self;
206
207 fn neg(self) -> Self::Output {
208 debug_assert!(self.is_simplified());
209 Self {
210 negated: !self.negated,
211 numerator: self.numerator,
212 denominator: self.denominator,
213 }
214 }
215}
216
217impl Eq for Fraction {}
218
219impl Add for Fraction {
220 type Output = Self;
221
222 fn add(self, rhs: Self) -> Self::Output {
223 if self.negated == rhs.negated {
224 Fraction::new(
225 self.numerator * rhs.denominator + rhs.numerator * self.denominator,
226 self.denominator * rhs.denominator,
227 self.negated,
228 )
229 } else {
230 let denominator = self.denominator * rhs.denominator;
231 let (negated, non_negated) = if self.negated {
232 (self, rhs)
233 } else {
234 (rhs, self)
235 };
236
237 if non_negated.numerator * negated.denominator
238 >= negated.numerator * non_negated.denominator
239 {
240 Fraction::new(
241 non_negated.numerator * negated.denominator
242 - negated.numerator * non_negated.denominator,
243 denominator,
244 false,
245 )
246 } else {
247 Fraction::new(
248 negated.numerator * non_negated.denominator
249 - non_negated.numerator * negated.denominator,
250 denominator,
251 true,
252 )
253 }
254 }
255 }
256}
257
258impl AddAssign for Fraction {
259 fn add_assign(&mut self, rhs: Self) {
260 *self = *self + rhs;
261 }
262}
263
264impl Sub for Fraction {
265 type Output = Self;
266
267 fn sub(self, rhs: Self) -> Self::Output {
268 self + (-rhs)
269 }
270}
271
272impl SubAssign for Fraction {
273 fn sub_assign(&mut self, rhs: Self) {
274 *self = *self - rhs;
275 }
276}
277
278impl Mul for Fraction {
279 type Output = Self;
280
281 fn mul(self, rhs: Self) -> Self::Output {
282 Fraction::new(
283 self.numerator * rhs.numerator,
284 self.denominator * rhs.denominator,
285 self.negated ^ rhs.negated,
286 )
287 }
288}
289
290impl MulAssign for Fraction {
291 fn mul_assign(&mut self, rhs: Self) {
292 *self = *self * rhs;
293 }
294}
295
296impl Div for Fraction {
297 type Output = Self;
298
299 #[allow(clippy::suspicious_arithmetic_impl)]
300 fn div(self, rhs: Self) -> Self::Output {
301 self * Fraction::new(rhs.denominator, rhs.numerator, rhs.negated)
302 }
303}
304
305impl DivAssign for Fraction {
306 fn div_assign(&mut self, rhs: Self) {
307 *self = *self / rhs;
308 }
309}
310
311impl From<u32> for Fraction {
312 fn from(value: u32) -> Self {
313 Fraction {
314 negated: false,
315 numerator: value,
316 denominator: 1,
317 }
318 }
319}
320
321impl PartialOrd for Fraction {
322 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
323 Some(self.cmp(other))
324 }
325}
326
327impl Ord for Fraction {
328 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
329 let a = self.numerator * other.denominator;
330 let b = other.numerator * self.denominator;
331
332 if self.negated && !other.negated {
333 return Ordering::Less;
334 }
335
336 if !self.negated && other.negated {
337 return Ordering::Greater;
338 }
339
340 if self.negated && other.negated {
341 return a.cmp(&b).reverse();
343 }
344 a.cmp(&b)
345 }
346}
347
348impl TryFrom<Fraction> for i64 {
349 type Error = ();
350
351 fn try_from(value: Fraction) -> Result<Self, Self::Error> {
353 if value.numerator.is_multiple_of(value.denominator) {
354 let mut res = value.numerator as i64 / value.denominator as i64;
355
356 if value.negated {
357 res = -res;
358 }
359
360 Ok(res)
361 } else {
362 Err(())
363 }
364 }
365}
366
367impl<T: Atomic> From<Fraction> for IntegerExpression<T> {
368 fn from(value: Fraction) -> Self {
369 if let Ok(c) = i64::try_from(value) {
371 if c < 0 {
372 return -IntegerExpression::Const(-c as u32);
373 } else {
374 return IntegerExpression::Const(c as u32);
375 }
376 }
377
378 let mut expr =
380 IntegerExpression::Const(value.numerator) / IntegerExpression::Const(value.denominator);
381
382 if value.negated {
383 expr = -expr;
384 }
385
386 expr
387 }
388}
389
390#[cfg(test)]
391mod tests {
392
393 use crate::expressions::Variable;
394
395 use super::*;
396
397 #[test]
398 fn test_fraction_getters() {
399 let f = Fraction::new(4, 8, false);
400 assert_eq!(f.numerator(), 1);
401 assert_eq!(f.denominator(), 2);
402 assert!(!f.is_negative());
403
404 let f = Fraction::new(12, 9, true);
405 assert_eq!(f.numerator(), 4);
406 assert_eq!(f.denominator(), 3);
407 }
408
409 #[test]
410 fn test_fraction_is_integer() {
411 let f1 = Fraction::new(4, 2, false);
412 assert!(f1.is_integer());
413 let f2 = Fraction::new(5, 2, false);
414 assert!(!f2.is_integer());
415 let f3 = Fraction::new(0, 1, false);
416 assert!(f3.is_integer());
417 let f4 = Fraction::new(0, 0, false);
418 assert!(f4.is_integer()); }
420
421 #[test]
422 fn test_simplification_for_div_by_zero() {
423 let f1 = Fraction::new(42, 0, true);
424 let f2 = Fraction::new(1, 0, false);
425 assert_eq!(f1, f2);
426 }
427
428 #[test]
429 fn test_fraction_addition() {
430 let f1 = Fraction::new(1, 2, false);
431 let f2 = Fraction::new(1, 3, false);
432 let result = f1 + f2;
433 assert_eq!(result.numerator, 5);
434 assert_eq!(result.denominator, 6);
435 assert!(!result.negated);
436
437 let f1 = Fraction::new(5, 10, false);
438 let f2 = Fraction::new(10, 30, true);
439 let result = f1 + f2;
440 assert_eq!(result.numerator, 1);
441 assert_eq!(result.denominator, 6);
442 assert!(!result.negated);
443
444 let f1 = Fraction::new(3, 6, true);
445 let f2 = Fraction::new(1, 3, false);
446 let result = f1 + f2;
447 assert_eq!(result.numerator, 1);
448 assert_eq!(result.denominator, 6);
449 assert!(result.negated);
450
451 let mut f1 = Fraction::new(3, 6, true);
452 let f2 = Fraction::new(2, 8, true);
453 f1 += f2;
454 assert_eq!(f1.numerator, 3);
455 assert_eq!(f1.denominator, 4);
456 assert!(f1.negated);
457 }
458
459 #[test]
460 fn test_fraction_subtraction() {
461 let f1 = Fraction::new(100, 200, false);
462 let f2 = Fraction::new(10, 30, false);
463 let result = f1 - f2;
464 assert_eq!(result.numerator, 1);
465 assert_eq!(result.denominator, 6);
466 assert!(!result.negated);
467
468 let f1 = Fraction::new(9, 18, false);
469 let f2 = Fraction::new(1, 3, true);
470 let result = f1 - f2;
471 assert_eq!(result.numerator, 5);
472 assert_eq!(result.denominator, 6);
473 assert!(!result.negated);
474
475 let mut f1 = Fraction::new(3, 6, true);
476 let f2 = Fraction::new(1, 3, false);
477 f1 -= f2;
478 assert_eq!(f1.numerator, 5);
479 assert_eq!(f1.denominator, 6);
480 assert!(f1.negated);
481 }
482
483 #[test]
484 fn test_fraction_multiplication() {
485 let f1 = Fraction::new(1, 2, false);
486 let f2 = Fraction::new(1, 3, false);
487 let result = f1 * f2;
488 assert_eq!(result.numerator, 1);
489 assert_eq!(result.denominator, 6);
490 assert!(!result.negated);
491
492 let f1 = Fraction::new(1, 2, false);
493 let f2 = Fraction::new(5, 15, true);
494 let result = f1 * f2;
495 assert_eq!(result.numerator, 1);
496 assert_eq!(result.denominator, 6);
497 assert!(result.negated);
498
499 let f1 = Fraction::new(1, 2, true);
500 let f2 = Fraction::new(1, 3, true);
501 let result = f1 * f2;
502 assert_eq!(result.numerator, 1);
503 assert_eq!(result.denominator, 6);
504 assert!(!result.negated);
505
506 let mut f1 = Fraction::new(1, 2, false);
507 let f2 = Fraction::new(1, 3, true);
508 f1 *= f2;
509 assert_eq!(f1.numerator, 1);
510 assert_eq!(f1.denominator, 6);
511 assert!(f1.negated);
512 }
513
514 #[test]
515 fn test_fraction_division() {
516 let f1 = Fraction::new(1, 2, false);
517 let f2 = Fraction::new(1, 3, false);
518 let result = f1 / f2;
519 assert_eq!(result.numerator, 3);
520 assert_eq!(result.denominator, 2);
521 assert!(!result.negated);
522
523 let f1 = Fraction::new(5, 10, false);
524 let f2 = Fraction::new(20, 40, false);
525 let result = f1 / f2;
526 assert_eq!(result.numerator, 1);
527 assert_eq!(result.denominator, 1);
528
529 let mut f1 = Fraction::new(1, 2, false);
530 let f2 = Fraction::new(1, 3, true);
531 f1 /= f2;
532 assert_eq!(f1.numerator, 3);
533 assert_eq!(f1.denominator, 2);
534 assert!(f1.negated);
535 }
536
537 #[test]
538 fn test_fraction_negation() {
539 let f1 = Fraction::new(1, 2, false);
540 let result = -f1;
541 assert_eq!(result.numerator, 1);
542 assert_eq!(result.denominator, 2);
543 assert!(result.negated);
544 }
545
546 #[test]
547 fn test_fraction_addition_with_negation() {
548 let f1 = Fraction::new(1, 2, false);
549 let f2 = Fraction::new(1, 3, true);
550 let result = f1 + f2;
551 assert_eq!(result.numerator, 1);
552 assert_eq!(result.denominator, 6);
553 assert!(!result.negated);
554 }
555
556 #[test]
557 fn test_fraction_subtraction_with_negation() {
558 let f1 = Fraction::new(1, 2, false);
559 let f2 = Fraction::new(1, 3, true);
560 let result = f1 - f2;
561 assert_eq!(result.numerator, 5);
562 assert_eq!(result.denominator, 6);
563 assert!(!result.negated);
564 }
565
566 #[test]
567 fn test_fraction_multiplication_with_negation() {
568 let f1 = Fraction::new(1, 2, false);
569 let f2 = Fraction::new(1, 3, true);
570 let result = f1 * f2;
571 assert_eq!(result.numerator, 1);
572 assert_eq!(result.denominator, 6);
573 assert!(result.negated);
574 }
575
576 #[test]
577 fn test_fraction_division_with_negation() {
578 let f1 = Fraction::new(1, 2, false);
579 let f2 = Fraction::new(1, 3, true);
580 let result = f1 / f2;
581 assert_eq!(result.numerator, 3);
582 assert_eq!(result.denominator, 2);
583 assert!(result.negated);
584 }
585
586 #[test]
587 fn test_fraction_simplification() {
588 let f = Fraction::new(4, 8, false).canonicalize();
589 assert_eq!(f.numerator, 1);
590 assert_eq!(f.denominator, 2);
591 assert!(!f.negated);
592 }
593
594 #[test]
595 fn test_fraction_eq() {
596 let f1 = Fraction::new(1, 2, false);
597 let f2 = Fraction::new(1, 2, false);
598 assert_eq!(f1, f2);
599
600 let f1 = Fraction::new(1, 2, false);
601 let f2 = Fraction::new(1, 2, true);
602 assert_ne!(f1, f2);
603
604 let f1 = Fraction::new(1, 2, false);
605 let f2 = Fraction::new(2, 4, false);
606 assert_eq!(f1, f2);
607
608 let f1 = Fraction::new(1, 2, false);
609 let f2 = Fraction::new(2, 4, true);
610 assert_ne!(f1, f2);
611
612 let f1 = Fraction::new(0, 2, true);
613 let f2 = Fraction::new(0, 2, false);
614 assert_eq!(f1, f2);
615
616 let f1 = Fraction::new(0, 2, true);
617 let f2 = Fraction::new(0, 3, true);
618 assert_eq!(f1, f2);
619 }
620
621 #[test]
622 fn test_fraction_simplification_with_negation() {
623 let f = Fraction::new(4, 8, true).canonicalize();
624 assert_eq!(f.numerator, 1);
625 assert_eq!(f.denominator, 2);
626 assert!(f.negated);
627 }
628
629 #[test]
630 fn test_fraction_from_u32() {
631 let f: Fraction = 5u32.into();
632 assert_eq!(f.numerator, 5);
633 assert_eq!(f.denominator, 1);
634 assert!(!f.negated);
635 }
636
637 #[test]
638 fn test_fraction_try_into_i64_success() {
639 let f = Fraction::new(4, 2, false);
640 let result: Result<i64, ()> = f.try_into();
641 assert_eq!(result.unwrap(), 2);
642 }
643
644 #[test]
645 fn test_fraction_try_into_i64_failure() {
646 let f = Fraction::new(5, 2, false);
647 let result: Result<i64, ()> = f.try_into();
648 assert!(result.is_err());
649 }
650
651 #[test]
652 fn test_fraction_try_into_i64_negated() {
653 let f = Fraction::new(4, 2, true);
654 let result: Result<i64, ()> = f.try_into();
655 assert_eq!(result.unwrap(), -2);
656 }
657
658 #[test]
659 fn test_fraction_display() {
660 let f = Fraction::new(1, 2, false);
661 assert_eq!(f.to_string(), "1/2");
662
663 let f = Fraction::new(1, 2, true);
664 assert_eq!(f.to_string(), "-1/2");
665
666 let f = Fraction::new(1, 1, false);
667 assert_eq!(f.to_string(), "1");
668 }
669
670 #[test]
671 fn test_fraction_into_integer_expression() {
672 let f = Fraction::new(1, 2, false);
673 let expr: IntegerExpression<Variable> = f.into();
674 assert_eq!(
675 expr,
676 IntegerExpression::Const(1) / IntegerExpression::Const(2)
677 );
678
679 let f = Fraction::new(1, 2, true);
680 let expr: IntegerExpression<Variable> = f.into();
681 assert_eq!(
682 expr,
683 -(IntegerExpression::Const(1) / IntegerExpression::Const(2))
684 );
685
686 let f = Fraction::new(1, 1, false);
687 let expr: IntegerExpression<Variable> = f.into();
688 assert_eq!(expr, IntegerExpression::Const(1));
689
690 let f = Fraction::new(1, 1, true);
691 let expr: IntegerExpression<Variable> = f.into();
692 assert_eq!(expr, -IntegerExpression::Const(1));
693 }
694
695 #[test]
696 fn test_inverse() {
697 let f = Fraction::new(1, 2, true);
698 let expected = Fraction::new(2, 1, true);
699 assert_eq!(f.inverse(), expected);
700
701 let f = Fraction::new(1, 2, false);
702 let expected = Fraction::new(2, 1, false);
703 assert_eq!(f.inverse(), expected);
704 }
705
706 #[test]
707 #[should_panic]
708 fn test_inverse_panics_on_0_numerator() {
709 let f = Fraction::new(0, 2, true);
710 let _ = f.inverse();
711 }
712
713 #[test]
714 fn test_fraction_ord() {
715 let f1 = Fraction::new(1, 2, false);
716 let f2 = Fraction::new(1, 2, false);
717 assert_eq!(f1.cmp(&f2), Ordering::Equal);
718 assert_eq!(f2.cmp(&f1), Ordering::Equal);
719
720 let f1 = Fraction::new(1, 2, true);
721 let f2 = Fraction::new(1, 2, true);
722 assert_eq!(f1.cmp(&f2), Ordering::Equal);
723 assert_eq!(f2.cmp(&f1), Ordering::Equal);
724
725 let f1 = Fraction::new(1, 2, true);
726 let f2 = Fraction::new(1, 2, false);
727 assert_eq!(f1.cmp(&f2), Ordering::Less);
728 assert_eq!(f2.cmp(&f1), Ordering::Greater);
729
730 let f1 = Fraction::new(1, 2, false);
731 let f2 = Fraction::new(2, 2, false);
732 assert_eq!(f1.cmp(&f2), Ordering::Less);
733 assert_eq!(f2.cmp(&f1), Ordering::Greater);
734
735 let f1 = Fraction::new(1, 4, false);
736 let f2 = Fraction::new(1, 2, false);
737 assert_eq!(f1.cmp(&f2), Ordering::Less);
738 assert_eq!(f2.cmp(&f1), Ordering::Greater);
739 }
740}