Skip to content

catena.views

views.convergents

Convergent view classes for simple continued fractions.

This module provides two accessor classes that expose convergent utilities under a dedicated scf.convergents sub-namespace, keeping the main SCF class lean while remaining discoverable via tab-completion:

  • :class:ConvergentsView — point-access and scalar queries for infinite (or generative) :class:~catena.catena.SimpleContinuedFraction instances.
  • :class:FiniteConvergentView — extends :class:ConvergentsView with iteration, slicing, and bulk lazy sequences for :class:~catena.catena.FiniteSimpleContinuedFraction instances.

Both classes are lightweight wrappers (__slots__) that hold a single reference to the underlying SCF; they perform no computation themselves.

ConvergentsView

Accessor for point-wise convergent queries on a :class:~catena.catena.SimpleContinuedFraction.

Obtained via scf.convergents. Exposes scalar lookups and type conversions for individual convergents without polluting the main SCF namespace. All methods delegate to :meth:~catena.catena.SimpleContinuedFraction.convergent, which is memoised, so repeated calls at the same index are O(1).

This class is intended for infinite (generative) SCFs. For finite SCFs, use :class:FiniteConvergentView, which additionally supports iteration, slicing, and bulk lazy sequences.

Source code in catena/views/convergents.py
 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
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
class ConvergentsView:
    """
    Accessor for point-wise convergent queries on a
    :class:`~catena.catena.SimpleContinuedFraction`.

    Obtained via ``scf.convergents``.  Exposes scalar lookups and type
    conversions for individual convergents without polluting the main SCF
    namespace.  All methods delegate to
    :meth:`~catena.catena.SimpleContinuedFraction.convergent`, which is
    memoised, so repeated calls at the same index are O(1).

    This class is intended for infinite (generative) SCFs.  For finite SCFs,
    use :class:`FiniteConvergentView`, which additionally supports iteration,
    slicing, and bulk lazy sequences.
    """
    __slots__ = ('_scf',)

    def __init__(self, scf: 'SimpleContinuedFraction'):
        """
        Initialises the view.

        Args:
            scf (SimpleContinuedFraction): The SCF instance to wrap.
        """
        #object.__setattr__(self, '_scf', scf)
        self._scf = scf

    def __getitem__(self, n: int) -> tuple[int, int]:
        """
        Returns the *n*-th convergent ``(pₙ, qₙ)`` of the SCF.

        Args:
            n (int): 0-indexed convergent depth.

        Returns:
            tuple[int, int]: ``(numerator, denominator)`` of the *n*-th
            convergent.

        Raises:
            TypeError: If ``n`` is a slice (slicing requires a finite bound;
                use a loop or list comprehension instead).
        """
        if isinstance(n, slice):
            raise TypeError(
                "Slicing is not supported on an infinite SCF view. "
                "Use a loop or list comprehension instead."
            )
        return self._scf.convergent(n)

    def as_decimal(self, n: int) -> Decimal:
        """
        Returns the *n*-th convergent as an exact :class:`~decimal.Decimal`.

        Args:
            n (int): 0-indexed convergent depth.

        Returns:
            Decimal: Exact rational value ``pₙ / qₙ``.
        """
        p, q = self._scf.convergent(n)
        return Decimal(p) / Decimal(q)

    def as_float(self, n: int) -> float:
        """
        Returns the *n*-th convergent as a Python :class:`float`.

        Args:
            n (int): 0-indexed convergent depth.

        Returns:
            float: Floating-point approximation of ``pₙ / qₙ``.
        """
        p, q = self._scf.convergent(n)
        return p / q

    def as_fraction(self, n: int) -> Fraction:
        """
        Returns the *n*-th convergent as a :class:`~fractions.Fraction`.

        Args:
            n (int): 0-indexed convergent depth.

        Returns:
            Fraction: Exact rational value ``pₙ / qₙ``.
        """
        p, q = self._scf.convergent(n)
        return Fraction(p, q)

    def as_digits(self, n: int, digits: int) -> str:
        """
        Returns the *n*-th convergent as a fixed-point decimal string.

        Uses an extended-precision :class:`~decimal.Decimal` context
        internally to avoid rounding artefacts in the last digit.

        Args:
            n (int): 0-indexed convergent depth.
            digits (int): Number of decimal places in the output string.

        Returns:
            str: The value ``pₙ / qₙ`` formatted to ``digits`` decimal places.
        """
        p, q = self._scf.convergent(n)
        with localcontext() as ctx:
            ctx.prec = digits + 10
            decimal_value = Decimal(p) / Decimal(q)
            return format(decimal_value, f'.{digits}f')

    def numerator_length(self, n: int) -> int:
        """
        Returns the number of decimal digits in the numerator of the *n*-th
        convergent.

        Args:
            n (int): 0-indexed convergent depth.

        Returns:
            int: ``⌊log₁₀ pₙ⌋ + 1``, or ``1`` when ``pₙ ≤ 0``.
        """
        p, _ = self._scf.convergent(n)
        return int(log10(p)) + 1 if p > 0 else 1

    def denominator_length(self, n: int) -> int:
        """
        Returns the number of decimal digits in the denominator of the *n*-th
        convergent.

        Args:
            n (int): 0-indexed convergent depth.

        Returns:
            int: ``⌊log₁₀ qₙ⌋ + 1``, or ``1`` when ``qₙ ≤ 0``.
        """
        _, q = self._scf.convergent(n)
        return int(log10(q)) + 1 if q > 0 else 1

__getitem__(n)

Returns the n-th convergent (pₙ, qₙ) of the SCF.

Parameters:

Name Type Description Default
n int

0-indexed convergent depth.

required

Returns:

Type Description
int

tuple[int, int]: (numerator, denominator) of the n-th

int

convergent.

Raises:

Type Description
TypeError

If n is a slice (slicing requires a finite bound; use a loop or list comprehension instead).

Source code in catena/views/convergents.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
def __getitem__(self, n: int) -> tuple[int, int]:
    """
    Returns the *n*-th convergent ``(pₙ, qₙ)`` of the SCF.

    Args:
        n (int): 0-indexed convergent depth.

    Returns:
        tuple[int, int]: ``(numerator, denominator)`` of the *n*-th
        convergent.

    Raises:
        TypeError: If ``n`` is a slice (slicing requires a finite bound;
            use a loop or list comprehension instead).
    """
    if isinstance(n, slice):
        raise TypeError(
            "Slicing is not supported on an infinite SCF view. "
            "Use a loop or list comprehension instead."
        )
    return self._scf.convergent(n)

__init__(scf)

Initialises the view.

Parameters:

Name Type Description Default
scf SimpleContinuedFraction

The SCF instance to wrap.

required
Source code in catena/views/convergents.py
51
52
53
54
55
56
57
58
59
def __init__(self, scf: 'SimpleContinuedFraction'):
    """
    Initialises the view.

    Args:
        scf (SimpleContinuedFraction): The SCF instance to wrap.
    """
    #object.__setattr__(self, '_scf', scf)
    self._scf = scf

as_decimal(n)

Returns the n-th convergent as an exact :class:~decimal.Decimal.

Parameters:

Name Type Description Default
n int

0-indexed convergent depth.

required

Returns:

Name Type Description
Decimal Decimal

Exact rational value pₙ / qₙ.

Source code in catena/views/convergents.py
83
84
85
86
87
88
89
90
91
92
93
94
def as_decimal(self, n: int) -> Decimal:
    """
    Returns the *n*-th convergent as an exact :class:`~decimal.Decimal`.

    Args:
        n (int): 0-indexed convergent depth.

    Returns:
        Decimal: Exact rational value ``pₙ / qₙ``.
    """
    p, q = self._scf.convergent(n)
    return Decimal(p) / Decimal(q)

as_digits(n, digits)

Returns the n-th convergent as a fixed-point decimal string.

Uses an extended-precision :class:~decimal.Decimal context internally to avoid rounding artefacts in the last digit.

Parameters:

Name Type Description Default
n int

0-indexed convergent depth.

required
digits int

Number of decimal places in the output string.

required

Returns:

Name Type Description
str str

The value pₙ / qₙ formatted to digits decimal places.

Source code in catena/views/convergents.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def as_digits(self, n: int, digits: int) -> str:
    """
    Returns the *n*-th convergent as a fixed-point decimal string.

    Uses an extended-precision :class:`~decimal.Decimal` context
    internally to avoid rounding artefacts in the last digit.

    Args:
        n (int): 0-indexed convergent depth.
        digits (int): Number of decimal places in the output string.

    Returns:
        str: The value ``pₙ / qₙ`` formatted to ``digits`` decimal places.
    """
    p, q = self._scf.convergent(n)
    with localcontext() as ctx:
        ctx.prec = digits + 10
        decimal_value = Decimal(p) / Decimal(q)
        return format(decimal_value, f'.{digits}f')

as_float(n)

Returns the n-th convergent as a Python :class:float.

Parameters:

Name Type Description Default
n int

0-indexed convergent depth.

required

Returns:

Name Type Description
float float

Floating-point approximation of pₙ / qₙ.

Source code in catena/views/convergents.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def as_float(self, n: int) -> float:
    """
    Returns the *n*-th convergent as a Python :class:`float`.

    Args:
        n (int): 0-indexed convergent depth.

    Returns:
        float: Floating-point approximation of ``pₙ / qₙ``.
    """
    p, q = self._scf.convergent(n)
    return p / q

as_fraction(n)

Returns the n-th convergent as a :class:~fractions.Fraction.

Parameters:

Name Type Description Default
n int

0-indexed convergent depth.

required

Returns:

Name Type Description
Fraction Fraction

Exact rational value pₙ / qₙ.

Source code in catena/views/convergents.py
109
110
111
112
113
114
115
116
117
118
119
120
def as_fraction(self, n: int) -> Fraction:
    """
    Returns the *n*-th convergent as a :class:`~fractions.Fraction`.

    Args:
        n (int): 0-indexed convergent depth.

    Returns:
        Fraction: Exact rational value ``pₙ / qₙ``.
    """
    p, q = self._scf.convergent(n)
    return Fraction(p, q)

denominator_length(n)

Returns the number of decimal digits in the denominator of the n-th convergent.

Parameters:

Name Type Description Default
n int

0-indexed convergent depth.

required

Returns:

Name Type Description
int int

⌊log₁₀ qₙ⌋ + 1, or 1 when qₙ ≤ 0.

Source code in catena/views/convergents.py
156
157
158
159
160
161
162
163
164
165
166
167
168
def denominator_length(self, n: int) -> int:
    """
    Returns the number of decimal digits in the denominator of the *n*-th
    convergent.

    Args:
        n (int): 0-indexed convergent depth.

    Returns:
        int: ``⌊log₁₀ qₙ⌋ + 1``, or ``1`` when ``qₙ ≤ 0``.
    """
    _, q = self._scf.convergent(n)
    return int(log10(q)) + 1 if q > 0 else 1

numerator_length(n)

Returns the number of decimal digits in the numerator of the n-th convergent.

Parameters:

Name Type Description Default
n int

0-indexed convergent depth.

required

Returns:

Name Type Description
int int

⌊log₁₀ pₙ⌋ + 1, or 1 when pₙ ≤ 0.

Source code in catena/views/convergents.py
142
143
144
145
146
147
148
149
150
151
152
153
154
def numerator_length(self, n: int) -> int:
    """
    Returns the number of decimal digits in the numerator of the *n*-th
    convergent.

    Args:
        n (int): 0-indexed convergent depth.

    Returns:
        int: ``⌊log₁₀ pₙ⌋ + 1``, or ``1`` when ``pₙ ≤ 0``.
    """
    p, _ = self._scf.convergent(n)
    return int(log10(p)) + 1 if p > 0 else 1

FiniteConvergentView

Bases: ConvergentsView

Accessor for convergent queries on a :class:~catena.catena.FiniteSimpleContinuedFraction.

Extends :class:ConvergentsView with sequence-like access (iteration, negative indexing, slicing) and a family of bulk lazy generators via :meth:apply.

All bulk methods return lazy :class:~collections.abc.Iterator objects; computation is deferred until the caller iterates, and the caller may stop early without evaluating the full sequence.

Source code in catena/views/convergents.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
class FiniteConvergentView(ConvergentsView):
    """
    Accessor for convergent queries on a
    :class:`~catena.catena.FiniteSimpleContinuedFraction`.


    Extends :class:`ConvergentsView` with sequence-like access (iteration,
    negative indexing, slicing) and a family of bulk lazy generators via
    :meth:`apply`.

    All bulk methods return lazy :class:`~collections.abc.Iterator` objects;
    computation is deferred until the caller iterates, and the caller may
    stop early without evaluating the full sequence.
    """
    __slots__ = ()

    if TYPE_CHECKING:
        _scf: FiniteSimpleContinuedFraction

    def __init__(self, scf: 'FiniteSimpleContinuedFraction'):
        if not scf.is_finite:
            raise TypeError("FiniteConvergentView can only be used with finite SCF instances.")

        super().__init__(scf)

    @overload
    def __getitem__(self, n: int) -> tuple[int, int]: ...
    @overload
    def __getitem__(self, n: slice) -> list[tuple[int, int]]: ...
    @override
    def __getitem__(self, n: int | slice) -> tuple[int, int] | list[tuple[int, int]]:
        """
        Returns the *n*-th convergent, or a list of convergents for a slice.

        Args:
            n (int | slice): A 0-indexed convergent depth, a negative index
                (counted from the terminal convergent), or a :class:`slice`.

        Returns:
            tuple[int, int]: ``(pₙ, qₙ)`` for integer ``n``.
            list[tuple[int, int]]: Convergents in the slice range.
        """
        if isinstance(n, slice):
            return [self._scf.convergent(i) for i in range(*n.indices(self._scf.size))]
        if n < 0:
            n += self._scf.size
        return self._scf.convergent(n)

    def __iter__(self) -> Iterator[tuple[int, int]]:
        """Yields all convergents ``(pₙ, qₙ)`` from ``n = 0`` to ``size - 1``."""
        for i in range(len(self)):
            yield self._scf.convergent(i)

    def __len__(self) -> int:
        """Returns the number of convergents (equal to ``scf.size``)."""
        return self._scf.size

    def apply(self, f: Callable[[int, int], T]) -> Iterator[T]:
        """
        Lazily applies ``f(p, q)`` to each convergent ``(p, q)`` in order.

        Nothing is computed until the caller iterates the result; the caller
        may stop at any point without evaluating the remaining convergents.
        This method also serves as an escape hatch for custom per-convergent
        metrics not covered by the named helper methods.

        Args:
            f (Callable[[int, int], T]): A function that takes a numerator
                ``p`` and denominator ``q`` and returns a value of type ``T``.

        Returns:
            Iterator[T]: A lazy iterator of ``f(pₙ, qₙ)`` for each ``n``.

        Example::

            # custom metric: parity of the denominator
            scf.convergents.apply(lambda _, q: q % 2)
        """
        return (f(p, q) for p, q in self)

    def as_decimals(self) -> Iterator[Decimal]:
        """
        Lazily yields each convergent as an exact :class:`~decimal.Decimal`.

        Returns:
            Iterator[Decimal]: ``pₙ / qₙ`` as a :class:`~decimal.Decimal`
            for each ``n``.
        """
        return self.apply(lambda p, q: Decimal(p) / Decimal(q))

    def as_floats(self) -> Iterator[float]:
        """
        Lazily yields each convergent as a Python :class:`float`.

        Returns:
            Iterator[float]: ``pₙ / qₙ`` as a :class:`float` for each ``n``.
        """
        return self.apply(lambda p, q: p / q)

    def as_fractions(self) -> Iterator[Fraction]:
        """
        Lazily yields each convergent as a :class:`~fractions.Fraction`.

        Returns:
            Iterator[Fraction]: ``pₙ / qₙ`` as a :class:`~fractions.Fraction`
            for each ``n``.
        """
        return self.apply(Fraction)

    def numerators(self) -> Iterator[int]:
        """
        Lazily yields the numerator of each convergent in order.

        Returns:
            Iterator[int]: ``pₙ`` for each ``n``.
        """
        return self.apply(lambda p, _: p)

    def denominators(self) -> Iterator[int]:
        """
        Lazily yields the denominator of each convergent in order.

        Returns:
            Iterator[int]: ``qₙ`` for each ``n``.
        """
        return self.apply(lambda _, q: q)

    def numerators_lengths(self) -> Iterator[int]:
        """
        Lazily yields the number of decimal digits in each numerator.

        Returns:
            Iterator[int]: ``⌊log₁₀ pₙ⌋ + 1`` (or ``1`` when ``pₙ ≤ 0``)
            for each ``n``.
        """
        return self.apply(lambda p, _: int(log10(p)) + 1 if p > 0 else 1)

    def denominators_lengths(self) -> Iterator[int]:
        """
        Lazily yields the number of decimal digits in each denominator.

        Returns:
            Iterator[int]: ``⌊log₁₀ qₙ⌋ + 1`` (or ``1`` when ``qₙ ≤ 0``)
            for each ``n``.
        """
        return self.apply(lambda _, q: int(log10(q)) + 1 if q > 0 else 1)

__getitem__(n)

__getitem__(n: int) -> tuple[int, int]
__getitem__(n: slice) -> list[tuple[int, int]]

Returns the n-th convergent, or a list of convergents for a slice.

Parameters:

Name Type Description Default
n int | slice

A 0-indexed convergent depth, a negative index (counted from the terminal convergent), or a :class:slice.

required

Returns:

Type Description
tuple[int, int] | list[tuple[int, int]]

tuple[int, int]: (pₙ, qₙ) for integer n.

tuple[int, int] | list[tuple[int, int]]

list[tuple[int, int]]: Convergents in the slice range.

Source code in catena/views/convergents.py
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
@override
def __getitem__(self, n: int | slice) -> tuple[int, int] | list[tuple[int, int]]:
    """
    Returns the *n*-th convergent, or a list of convergents for a slice.

    Args:
        n (int | slice): A 0-indexed convergent depth, a negative index
            (counted from the terminal convergent), or a :class:`slice`.

    Returns:
        tuple[int, int]: ``(pₙ, qₙ)`` for integer ``n``.
        list[tuple[int, int]]: Convergents in the slice range.
    """
    if isinstance(n, slice):
        return [self._scf.convergent(i) for i in range(*n.indices(self._scf.size))]
    if n < 0:
        n += self._scf.size
    return self._scf.convergent(n)

__iter__()

Yields all convergents (pₙ, qₙ) from n = 0 to size - 1.

Source code in catena/views/convergents.py
219
220
221
222
def __iter__(self) -> Iterator[tuple[int, int]]:
    """Yields all convergents ``(pₙ, qₙ)`` from ``n = 0`` to ``size - 1``."""
    for i in range(len(self)):
        yield self._scf.convergent(i)

__len__()

Returns the number of convergents (equal to scf.size).

Source code in catena/views/convergents.py
224
225
226
def __len__(self) -> int:
    """Returns the number of convergents (equal to ``scf.size``)."""
    return self._scf.size

apply(f)

Lazily applies f(p, q) to each convergent (p, q) in order.

Nothing is computed until the caller iterates the result; the caller may stop at any point without evaluating the remaining convergents. This method also serves as an escape hatch for custom per-convergent metrics not covered by the named helper methods.

Parameters:

Name Type Description Default
f Callable[[int, int], T]

A function that takes a numerator p and denominator q and returns a value of type T.

required

Returns:

Type Description
Iterator[T]

Iterator[T]: A lazy iterator of f(pₙ, qₙ) for each n.

Example::

# custom metric: parity of the denominator
scf.convergents.apply(lambda _, q: q % 2)
Source code in catena/views/convergents.py
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
def apply(self, f: Callable[[int, int], T]) -> Iterator[T]:
    """
    Lazily applies ``f(p, q)`` to each convergent ``(p, q)`` in order.

    Nothing is computed until the caller iterates the result; the caller
    may stop at any point without evaluating the remaining convergents.
    This method also serves as an escape hatch for custom per-convergent
    metrics not covered by the named helper methods.

    Args:
        f (Callable[[int, int], T]): A function that takes a numerator
            ``p`` and denominator ``q`` and returns a value of type ``T``.

    Returns:
        Iterator[T]: A lazy iterator of ``f(pₙ, qₙ)`` for each ``n``.

    Example::

        # custom metric: parity of the denominator
        scf.convergents.apply(lambda _, q: q % 2)
    """
    return (f(p, q) for p, q in self)

as_decimals()

Lazily yields each convergent as an exact :class:~decimal.Decimal.

Returns:

Type Description
Iterator[Decimal]

Iterator[Decimal]: pₙ / qₙ as a :class:~decimal.Decimal

Iterator[Decimal]

for each n.

Source code in catena/views/convergents.py
251
252
253
254
255
256
257
258
259
def as_decimals(self) -> Iterator[Decimal]:
    """
    Lazily yields each convergent as an exact :class:`~decimal.Decimal`.

    Returns:
        Iterator[Decimal]: ``pₙ / qₙ`` as a :class:`~decimal.Decimal`
        for each ``n``.
    """
    return self.apply(lambda p, q: Decimal(p) / Decimal(q))

as_floats()

Lazily yields each convergent as a Python :class:float.

Returns:

Type Description
Iterator[float]

Iterator[float]: pₙ / qₙ as a :class:float for each n.

Source code in catena/views/convergents.py
261
262
263
264
265
266
267
268
def as_floats(self) -> Iterator[float]:
    """
    Lazily yields each convergent as a Python :class:`float`.

    Returns:
        Iterator[float]: ``pₙ / qₙ`` as a :class:`float` for each ``n``.
    """
    return self.apply(lambda p, q: p / q)

as_fractions()

Lazily yields each convergent as a :class:~fractions.Fraction.

Returns:

Type Description
Iterator[Fraction]

Iterator[Fraction]: pₙ / qₙ as a :class:~fractions.Fraction

Iterator[Fraction]

for each n.

Source code in catena/views/convergents.py
270
271
272
273
274
275
276
277
278
def as_fractions(self) -> Iterator[Fraction]:
    """
    Lazily yields each convergent as a :class:`~fractions.Fraction`.

    Returns:
        Iterator[Fraction]: ``pₙ / qₙ`` as a :class:`~fractions.Fraction`
        for each ``n``.
    """
    return self.apply(Fraction)

denominators()

Lazily yields the denominator of each convergent in order.

Returns:

Type Description
Iterator[int]

Iterator[int]: qₙ for each n.

Source code in catena/views/convergents.py
289
290
291
292
293
294
295
296
def denominators(self) -> Iterator[int]:
    """
    Lazily yields the denominator of each convergent in order.

    Returns:
        Iterator[int]: ``qₙ`` for each ``n``.
    """
    return self.apply(lambda _, q: q)

denominators_lengths()

Lazily yields the number of decimal digits in each denominator.

Returns:

Type Description
Iterator[int]

Iterator[int]: ⌊log₁₀ qₙ⌋ + 1 (or 1 when qₙ ≤ 0)

Iterator[int]

for each n.

Source code in catena/views/convergents.py
308
309
310
311
312
313
314
315
316
def denominators_lengths(self) -> Iterator[int]:
    """
    Lazily yields the number of decimal digits in each denominator.

    Returns:
        Iterator[int]: ``⌊log₁₀ qₙ⌋ + 1`` (or ``1`` when ``qₙ ≤ 0``)
        for each ``n``.
    """
    return self.apply(lambda _, q: int(log10(q)) + 1 if q > 0 else 1)

numerators()

Lazily yields the numerator of each convergent in order.

Returns:

Type Description
Iterator[int]

Iterator[int]: pₙ for each n.

Source code in catena/views/convergents.py
280
281
282
283
284
285
286
287
def numerators(self) -> Iterator[int]:
    """
    Lazily yields the numerator of each convergent in order.

    Returns:
        Iterator[int]: ``pₙ`` for each ``n``.
    """
    return self.apply(lambda p, _: p)

numerators_lengths()

Lazily yields the number of decimal digits in each numerator.

Returns:

Type Description
Iterator[int]

Iterator[int]: ⌊log₁₀ pₙ⌋ + 1 (or 1 when pₙ ≤ 0)

Iterator[int]

for each n.

Source code in catena/views/convergents.py
298
299
300
301
302
303
304
305
306
def numerators_lengths(self) -> Iterator[int]:
    """
    Lazily yields the number of decimal digits in each numerator.

    Returns:
        Iterator[int]: ``⌊log₁₀ pₙ⌋ + 1`` (or ``1`` when ``pₙ ≤ 0``)
        for each ``n``.
    """
    return self.apply(lambda p, _: int(log10(p)) + 1 if p > 0 else 1)