malachite_q/conversion/continued_fraction/
to_continued_fraction.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 crate::conversion::traits::ContinuedFraction;
11use core::mem::swap;
12use malachite_base::num::arithmetic::traits::{DivMod, Floor};
13use malachite_nz::integer::Integer;
14use malachite_nz::natural::Natural;
15
16/// An iterator that produces the continued fraction of a [`Rational`].
17///
18/// See [`continued_fraction`](Rational::continued_fraction) for more information.
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct RationalContinuedFraction {
21    numerator: Natural,
22    denominator: Natural,
23}
24
25impl RationalContinuedFraction {
26    pub_crate_test! {is_done(&self) -> bool {
27        self.denominator == 0u32 || self.numerator == 0u32
28    }}
29}
30
31impl Iterator for RationalContinuedFraction {
32    type Item = Natural;
33
34    fn next(&mut self) -> Option<Natural> {
35        if self.denominator == 0u32 || self.numerator == 0u32 {
36            None
37        } else {
38            let n;
39            (n, self.numerator) = (&self.numerator).div_mod(&self.denominator);
40            swap(&mut self.numerator, &mut self.denominator);
41            Some(n)
42        }
43    }
44}
45
46impl ContinuedFraction for Rational {
47    type CF = RationalContinuedFraction;
48
49    /// Returns the continued fraction of a [`Rational`], taking the [`Rational`] by value.
50    ///
51    /// The output has two components. The first is the first value of the continued fraction, which
52    /// may be any [`Integer`] and is equal to the floor of the [`Rational`]. The second is an
53    /// iterator that produces the remaining values, which are all positive. Using the standard
54    /// notation for continued fractions, the first value is the number before the semicolon, and
55    /// the second value produces the remaining numbers.
56    ///
57    /// Each rational number has two continued fraction representations. The shorter of the two
58    /// representations (the one that does not end in 1) is returned.
59    ///
60    /// $f(x) = (a_0, (a_1, a_2, \ldots, a_3)),$ where $x = [a_0; a_1, a_2, \ldots, a_3]$ and $a_3
61    /// \neq 1$.
62    ///
63    /// The output length is $O(n)$, where $n$ is `self.significant_bits()`.
64    ///
65    /// # Worst-case complexity per iteration
66    /// $T(n) = O(n \log n \log\log n)$
67    ///
68    /// $M(n) = O(n \log n)$
69    ///
70    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
71    ///
72    /// # Examples
73    /// ```
74    /// use itertools::Itertools;
75    /// use malachite_base::strings::ToDebugString;
76    /// use malachite_q::conversion::traits::ContinuedFraction;
77    /// use malachite_q::Rational;
78    ///
79    /// let (head, tail) = Rational::from_signeds(2, 3).continued_fraction();
80    /// let tail = tail.collect_vec();
81    /// assert_eq!(head, 0);
82    /// assert_eq!(tail.to_debug_string(), "[1, 2]");
83    ///
84    /// let (head, tail) = Rational::from_signeds(355, 113).continued_fraction();
85    /// let tail = tail.collect_vec();
86    /// assert_eq!(head, 3);
87    /// assert_eq!(tail.to_debug_string(), "[7, 16]");
88    /// ```
89    fn continued_fraction(mut self) -> (Integer, RationalContinuedFraction) {
90        let f = (&self).floor();
91        self -= Rational::from(&f);
92        let (d, n) = self.into_numerator_and_denominator();
93        (
94            f,
95            RationalContinuedFraction {
96                numerator: n,
97                denominator: d,
98            },
99        )
100    }
101}
102
103impl ContinuedFraction for &Rational {
104    type CF = RationalContinuedFraction;
105
106    /// Returns the continued fraction of a [`Rational`], taking the [`Rational`] by reference.
107    ///
108    /// The output has two components. The first is the first value of the continued fraction, which
109    /// may be any [`Integer`] and is equal to the floor of the [`Rational`]. The second is an
110    /// iterator that produces the remaining values, which are all positive. Using the standard
111    /// notation for continued fractions, the first value is the number before the semicolon, and
112    /// the second value produces the remaining numbers.
113    ///
114    /// Each rational number has two continued fraction representations. The shorter of the two
115    /// representations (the one that does not end in 1) is returned.
116    ///
117    /// $f(x) = (a_0, (a_1, a_2, \ldots, a_3)),$ where $x = [a_0; a_1, a_2, \ldots, a_3]$ and $a_3
118    /// \neq 1$.
119    ///
120    /// The output length is $O(n)$, where $n$ is `self.significant_bits()`.
121    ///
122    /// # Worst-case complexity per iteration
123    /// $T(n) = O(n \log n \log\log n)$
124    ///
125    /// $M(n) = O(n \log n)$
126    ///
127    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
128    ///
129    /// # Examples
130    /// ```
131    /// use itertools::Itertools;
132    /// use malachite_base::strings::ToDebugString;
133    /// use malachite_q::conversion::traits::ContinuedFraction;
134    /// use malachite_q::Rational;
135    ///
136    /// let (head, tail) = (&Rational::from_signeds(2, 3)).continued_fraction();
137    /// let tail = tail.collect_vec();
138    /// assert_eq!(head, 0);
139    /// assert_eq!(tail.to_debug_string(), "[1, 2]");
140    ///
141    /// let (head, tail) = (&Rational::from_signeds(355, 113)).continued_fraction();
142    /// let tail = tail.collect_vec();
143    /// assert_eq!(head, 3);
144    /// assert_eq!(tail.to_debug_string(), "[7, 16]");
145    /// ```
146    fn continued_fraction(self) -> (Integer, RationalContinuedFraction) {
147        let f = self.floor();
148        let (d, n) = (self - Rational::from(&f)).into_numerator_and_denominator();
149        (
150            f,
151            RationalContinuedFraction {
152                numerator: n,
153                denominator: d,
154            },
155        )
156    }
157}