malachite_q/conversion/mutate_numerator_and_denominator.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::Rational;
10use malachite_base::num::arithmetic::traits::{DivExactAssign, Gcd};
11use malachite_nz::natural::Natural;
12
13impl Rational {
14 /// Mutates the numerator of a [`Rational`] using a provided closure, and then returns whatever
15 /// the closure returns.
16 ///
17 /// After the closure executes, this function reduces the [`Rational`].
18 ///
19 /// # Examples
20 /// ```
21 /// use malachite_base::num::basic::traits::One;
22 /// use malachite_nz::natural::Natural;
23 /// use malachite_q::Rational;
24 ///
25 /// let mut q = Rational::from_signeds(22, 7);
26 /// let ret = q.mutate_numerator(|x| {
27 /// *x -= Natural::ONE;
28 /// true
29 /// });
30 /// assert_eq!(q, 3);
31 /// assert_eq!(ret, true);
32 /// ```
33 pub fn mutate_numerator<F: FnOnce(&mut Natural) -> T, T>(&mut self, f: F) -> T {
34 let out = f(&mut self.numerator);
35 let gcd = (&self.numerator).gcd(&self.denominator);
36 self.numerator.div_exact_assign(&gcd);
37 self.denominator.div_exact_assign(gcd);
38 if !self.sign && self.numerator == 0 {
39 self.sign = true;
40 }
41 out
42 }
43
44 /// Mutates the denominator of a [`Rational`] using a provided closure, and then returns
45 /// whatever the closure returns.
46 ///
47 /// After the closure executes, this function reduces the [`Rational`].
48 ///
49 /// # Panics
50 /// Panics if the closure sets the denominator to zero.
51 ///
52 /// # Examples
53 /// ```
54 /// use malachite_base::num::basic::traits::One;
55 /// use malachite_nz::natural::Natural;
56 /// use malachite_q::Rational;
57 ///
58 /// let mut q = Rational::from_signeds(22, 7);
59 /// let ret = q.mutate_denominator(|x| {
60 /// *x -= Natural::ONE;
61 /// true
62 /// });
63 /// assert_eq!(q.to_string(), "11/3");
64 /// assert_eq!(ret, true);
65 /// ```
66 pub fn mutate_denominator<F: FnOnce(&mut Natural) -> T, T>(&mut self, f: F) -> T {
67 let out = f(&mut self.denominator);
68 assert_ne!(self.denominator, 0);
69 let gcd = (&self.numerator).gcd(&self.denominator);
70 self.numerator.div_exact_assign(&gcd);
71 self.denominator.div_exact_assign(gcd);
72 out
73 }
74
75 /// Mutates the numerator and denominator of a [`Rational`] using a provided closure, and then
76 /// returns whatever the closure returns.
77 ///
78 /// After the closure executes, this function reduces the [`Rational`].
79 ///
80 /// # Panics
81 /// Panics if the closure sets the denominator to zero.
82 ///
83 /// # Examples
84 /// ```
85 /// use malachite_base::num::basic::traits::One;
86 /// use malachite_nz::natural::Natural;
87 /// use malachite_q::Rational;
88 ///
89 /// let mut q = Rational::from_signeds(22, 7);
90 /// let ret = q.mutate_numerator_and_denominator(|x, y| {
91 /// *x -= Natural::ONE;
92 /// *y -= Natural::ONE;
93 /// true
94 /// });
95 /// assert_eq!(q.to_string(), "7/2");
96 /// assert_eq!(ret, true);
97 /// ```
98 pub fn mutate_numerator_and_denominator<F: FnOnce(&mut Natural, &mut Natural) -> T, T>(
99 &mut self,
100 f: F,
101 ) -> T {
102 let out = f(&mut self.numerator, &mut self.denominator);
103 assert_ne!(self.denominator, 0);
104 let gcd = (&self.numerator).gcd(&self.denominator);
105 self.numerator.div_exact_assign(&gcd);
106 self.denominator.div_exact_assign(gcd);
107 if !self.sign && self.numerator == 0 {
108 self.sign = true;
109 }
110 out
111 }
112}