FLINT3.7.0-dev

Continued fractions

Synopsis#include <flint/fmpq.h>
slong fmpq_get_cfrac(fmpz * c, fmpq_t rem, const fmpq_t x, slong n)source
slong fmpq_get_cfrac_naive(fmpz * c, fmpq_t rem, const fmpq_t x, slong n)source

Write the first k≤nk \le n terms of the simple continued fraction of xx to cc and the remainder to rem, and return kk. The expansion generated is the shorter of the two. fmpq_get_cfrac uses a half-GCD algorithm and runs in quasi-linear time, fmpq_get_cfrac_naive uses repeated division. See Continued fractions.

void fmpq_set_cfrac(fmpq_t x, const fmpz * c, slong n)source

Sets xx to the value of the continued fraction [c0;c1,…,cn−1][c_0; c_1, \ldots, c_{n-1}], for n>0n > 0 and positive c1,…,cn−1c_1, \ldots, c_{n-1}. Uses a balanced product of 2×22 \times 2 matrices. See Continued fractions.

slong fmpq_cfrac_bound(const fmpq_t x)source

Returns an upper bound for the number of terms of the continued fraction of xx: 1 for an integer, otherwise ⌊1.4404 b⌋+2\lfloor 1.4404\, b \rfloor + 2 where bb is the bit length of the denominator. The bound is not sharp.

A fraction whose shorter expansion has kk terms has denominator at least the Fibonacci number Fk+1≥φk−1F_{k+1} \ge \varphi^{k-1}, with equality for [c0;1,…,1,2][c_0; 1, \ldots, 1, 2]. The constant is 1/log⁡2φ1/\log_2 \varphi.

Every rational number xx has a finite simple continued fraction

x=c0+1c1+1c2+1⋱+1ck−1=[c0;c1,…,ck−1]x = c_0 + \cfrac{1}{c_1 + \cfrac{1}{c_2 + \cfrac{1}{\ddots + \cfrac{1}{c_{k-1}}}}} = [c_0; c_1, \ldots, c_{k-1}]

with c0=⌊x⌋∈Zc_0 = \lfloor x \rfloor \in \mathbb{Z} and c1,…,ck−1≥1c_1, \ldots, c_{k-1} \ge 1. The expansion is unique if the last term is required to be at least 2 (for k≥2k \ge 2); the other expansion replaces ck−1c_{k-1} by ck−1−1,1c_{k-1} - 1, 1. fmpq_get_cfrac computes the terms of the shorter expansion, fmpq_set_cfrac evaluates a continued fraction, and fmpq_cfrac_bound bounds the length, so that the caller can allocate the output vector.

AlgorithmContinued fractions of rational numbersComputes the continued fraction of a rational number with a half-GCD algorithm that finds the terms from leading bits, evaluates continued fractions by balanced matrix products, and uses the same machinery for the simplest fraction in an interval, Farey neighbours and Dedekind sums.

Computing the terms#

fmpq_get_cfrac(c, rem, x, n) writes at most nn terms to cc (which must have room for nn initialised fmpz), sets rem to the remainder rr, and returns the number kk of terms written, so that

x=[c0;c1,…,ck−2,ck−1+r],0≤r<1.x = [c_0; c_1, \ldots, c_{k-2}, c_{k-1} + r], \qquad 0 \le r < 1.

If r=0r = 0, the expansion is complete. If r≠0r \ne 0, then k=nk = n, and the expansion continues with the terms of 1/r1/r: passing 1/r1/r (computed with fmpq_inv) as the next input generates ck,ck+1,…c_k, c_{k+1}, \ldots, so that the terms can be extracted in chunks of any size. For canonical xx and n>0n > 0 the remainder is canonical, and k=nk = n or r=0r = 0; with n≥n \ge fmpq_cfrac_bound(x) the expansion is always complete.

The function uses a half-GCD algorithm (Continued fractions of rational numbers): it finds the terms from the leading bits of the numerator and denominator, recursively, and costs O(M(b)log⁡b)O(M(b) \log b) for bb-bit inputs, against O(b2)O(b^2) for the Euclidean algorithm in fmpq_get_cfrac_naive. The terms are written in batches, so the time to find the first few terms of a huge fraction is small.

With n≤0n \le 0 no term is written and rem is set to 1/x1/x, in canonical form for x≠0x \ne 0 (for example −2/3-2/3 for x=−3/2x = -3/2) and the non-canonical 1/01/0 for x=0x = 0, so that the convention of the remainder holds trivially.

Evaluating a continued fraction#

fmpq_set_cfrac(x, c, n) sets x=[c0;c1,…,cn−1]x = [c_0; c_1, \ldots, c_{n-1}], for n>0n > 0 and c1,…,cn−1c_1, \ldots, c_{n-1} positive (then the result is canonical). The numerator and denominator are the first column of the matrix product

(c0110)(c1110)⋯(cn−1110),\begin{pmatrix} c_0 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} c_1 & 1 \\ 1 & 0 \end{pmatrix} \cdots \begin{pmatrix} c_{n-1} & 1 \\ 1 & 0 \end{pmatrix},

which the function evaluates by splitting it in halves recursively, with the plain product below 32 factors. The balanced product has cost O(M(b)log⁡n)O(M(b) \log n) for a bb-bit result, where multiplying the factors one by one would cost O(nb)O(nb).

Bounding the length#

fmpq_cfrac_bound(x) returns 1 for an integer and ⌊1.4404 b⌋+2\lfloor 1.4404\, b \rfloor + 2 otherwise, where bb is the bit length of the denominator. It follows from the fact that a fraction whose shorter expansion has kk terms has denominator at least the Fibonacci number Fk+1F_{k+1}.

Example#

The terms of −103993/33102-103993/33102, a convergent of −π-\pi, are computed in two chunks, and the full expansion and a truncation are evaluated.

Examplefmpq_cfrac_basic.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpz_vec.h>
#include <flint/fmpq.h>

int main(void)
{
    fmpq_t x, r, y;
    fmpz * c;
    slong i, k, n, len;

    fmpq_init(x);
    fmpq_init(r);
    fmpq_init(y);

    fmpq_set_si(x, -103993, 33102);
    len = fmpq_cfrac_bound(x);
    c = _fmpz_vec_init(len);

    /* the first two terms and the remainder */
    k = fmpq_get_cfrac(c, r, x, 2);
    flint_printf("%wd terms, remainder ", k);
    fmpq_print(r);
    flint_printf("\n");

    /* continue with 1/r */
    fmpq_inv(r, r);
    n = k + fmpq_get_cfrac(c + k, r, r, len - k);
    flint_printf("terms:");
    for (i = 0; i < n; i++)
    {
        flint_printf(" ");
        fmpz_print(c + i);
    }
    flint_printf(" (bound %wd)\n", len);

    fmpq_set_cfrac(y, c, n);
    fmpq_print(y);
    flint_printf("\n");
    fmpq_set_cfrac(y, c, 4);
    fmpq_print(y);
    flint_printf("\n");

    _fmpz_vec_clear(c, len);
    fmpq_clear(x);
    fmpq_clear(r);
    fmpq_clear(y);
    return 0;
}
Output
2 terms, remainder 4687/28415
terms: -4 1 6 15 1 292 (bound 25)
-103993/33102
-333/106
Cite this page

The FLINT team, “Continued fractions (fmpq.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpq/cfrac.html (generated 2026-11-02).