FLINT3.7.0-dev

Euclidean division of limb arrays

Synopsis#include <flint/mpn_extras.h>
void flint_mpn_tdiv_qr(mp_ptr q, mp_ptr r, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source
void flint_mpn_tdiv_q(mp_ptr q, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source
void flint_mpn_tdiv_r(mp_ptr r, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source

Euclidean division: sets (q, \mathit{an} - \mathit{bn} + 1) to \lfloor a/b \rfloor and (r, \mathit{bn}) to a - qb. The quotient must not overlap the inputs. As with GMP's mpn_tdiv_qr, r may be equal to a (the remainder then overwrites the low \mathit{bn} limbs of a) but must not overlap b. These replace GMP's mpn_tdiv_qr and are faster for all sizes.

void flint_mpn_cdiv_qr(mp_ptr q, mp_ptr r, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source
void flint_mpn_cdiv_q(mp_ptr q, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source
void flint_mpn_cdiv_r(mp_ptr r, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source

Ceiling division: sets (q, \mathit{an} - \mathit{bn} + 2) to \lceil a/b \rceil and (r, \mathit{bn}) to qb - a \in [0, b). The quotient can overflow \mathit{an} - \mathit{bn} + 1 limbs (for example for a = B^2 - 1, b = B), so one extra limb, which is 0 or 1, is written. Aliasing as for flint_mpn_tdiv_qr.

int flint_mpn_ndiv_qr(mp_ptr q, mp_ptr r, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source
void flint_mpn_ndiv_q(mp_ptr q, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source
int flint_mpn_ndiv_r(mp_ptr r, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source

Division rounding to nearest, ties to even: sets (q, \mathit{an} - \mathit{bn} + 2) to the integer nearest to a/b and (r, \mathit{bn}) to |a - qb| \le b/2, and returns the sign (-1, 0 or 1) of a - qb. As for ceiling division, one extra quotient limb (0 or 1) is written.

void flint_mpn_divapprox(mp_ptr q, mp_srcptr a, mp_size_t an, mp_srcptr b, mp_size_t bn)source

Approximate quotient: sets (q, \mathit{an} - \mathit{bn} + 1) to \lfloor a/b \rfloor or \lfloor a/b \rfloor + 1, like GMP's internal mpn_divappr_q. No aliasing is permitted. This follows the algorithm selection of flint_mpn_tdiv_q, so that it is never slower, but skips the final corrections.

It uses _mp_real_div_newton with one guard limb, rounded up by more than its error bound, instead of the Newton division, and does so already instead of the divide and conquer or short division when both \mathit{bn} and \mathit{an} - \mathit{bn} + 1 are at least FLINT_MPN_DIVAPPROX_NEWTON_CUTOFF.

void flint_mpn_inv(mp_ptr q, mp_srcptr x, mp_size_t xn, mp_size_t n)source

Correctly truncated reciprocal: sets (q, n - \mathit{xn} + 2) to \lfloor B^n / x \rfloor. Requires x_{xn-1} \ne 0 and n \ge \mathit{xn}. The top output limb is nonzero only when x is a power of B.

One- and two-limb x use a chain of 2/1 or 3/2 divisions of zero limbs. Otherwise, when \min(\mathit{xn}, n - \mathit{xn} + 2) is below FLINT_MPN_INV_NEWTON_CUTOFF (quotients of at most \mathit{xn} + 2 limbs), FLINT_MPN_INV_NEWTON_LONG_CUTOFF (quotients of at most 6 \mathit{xn} limbs) or FLINT_MPN_INV_NEWTON_VERYLONG_CUTOFF (longer quotients), the quotient is computed by flint_mpn_tdiv_q (reading only the top O(n - \mathit{xn}) limbs of x for short quotients), and above by _mp_real_inv_newton with three extra fraction limbs and the certification and correction scheme of the Newton division, which avoids forming the numerator B^n in the common case.

flint_mpn_tdiv_qr replaces GMP's mpn_tdiv_qr, with the same interface and aliasing rules, and the other functions below are built on the same machinery. The division is done entirely by FLINT (except for GMP's assembly mpn_divrem_1 and, where it helps, mpn_divrem_2), which makes it faster than GMP's for all shapes, and asymptotically faster for huge operands, where it uses Newton iteration on top of the fft_small multiplication.

AlgorithmInteger division and Newton iterationEuclidean division of multiprecision integers by schoolbook division with a 3-by-2 inverse, Burnikel–Ziegler divide and conquer, and Newton iteration with the Karp–Markstein trick; exact division by 2-adic (Hensel) methods; division by a fixed divisor with a precomputed inverse; and square roots by the same techniques.

Algorithm selection#

With m = \mathit{an} - \mathit{bn} + 1 quotient limbs, _flint_mpn_tdiv_qr chooses, in this order:

  1. Register-based division (_flint_mpn_tdiv_qr_small) for divisors of at most 3 limbs, and for divisors of 4 to 7 limbs with short dividends (\mathit{an} \le 3\,\mathit{bn} when the remainder is wanted, \mathit{an} \le \mathit{bn} + 2 otherwise). The divisor and the partial remainder are kept in registers and each quotient limb takes one 3/2 division step [GraMol2010].
  2. Newton division when the divisor and the quotient both have at least FLINT_MPN_TDIV_QR_NEWTON_CUTOFF limbs (950 on x86-64), or the divisor has at least FLINT_MPN_TDIV_QR_NEWTON_LONG_CUTOFF limbs (608) and the quotient is at least twice as long: _flint_mpn_tdiv_qr_newton computes the quotient as a fixed-point number by Karp–Markstein iteration [KM1997] (_mp_real_div_newton) and certifies its integer part, or _flint_mpn_tdiv_qr_unbalanced if \mathit{an} \ge 3\,\mathit{bn}.
  3. Blockwise division with a shared inverse (_flint_mpn_tdiv_qr_unbalanced) for \mathit{an} \ge 4\,\mathit{bn} with \mathit{bn} \ge 64, or \mathit{an} \ge 3\,\mathit{bn} with \mathit{bn} \ge 512: the dividend is processed in blocks of 2\,\mathit{bn} \times \mathit{bn} divisions that all use one approximate inverse of b.
  4. Division with an n-limb precomputed inverse (_flint_mpn_tdiv_qr_preinvn) for short divisors and long dividends: \mathit{bn} \ge 32 and \mathit{an} \ge 4\,\mathit{bn}, or \mathit{bn} \ge 4 and \mathit{an} \ge 32\,\mathit{bn}.
  5. Otherwise schoolbook and divide and conquer division (_flint_mpn_tdiv_qr_divconquer, or _flint_mpn_tdiv_q_divconquer without the remainder): ports of GMP's code [BurZie1998] with FLINT's multiplication, and for quotients about as short as the divisor, a short division in the style of Mulders that only forms high products [HZ2011].

All cutoffs are machine dependent (flint-mparam.h, measured by src/mpn_extras/tune/tune-div.c); the values above are those for x86-64.

Where hardware division is fast (FLINT_PREINVERT_LIMB_USE_NATIVE, for example on AMD Zen 3 and later), limb inverses are computed with it, and short dividends use chains of hardware divisions instead of inverses: one-limb divisors below FLINT_MPN_DIVREM_1_HW_CUTOFF dividend limbs (FLINT_MPN_DIVREM_1_NORM_HW_CUTOFF for normalised divisors), two-limb divisors below FLINT_MPN_DIV_2_HW_CUTOFF limbs (a 3/2 step made of one hardware 2/1 division and a correction by the low divisor limb, as in Knuth's algorithm D, with normalisation on the fly), and 3- to 7-limb divisors for quotients shorter than FLINT_MPN_DIV_SMALL_HW_QN_CUTOFF. Two-limb divisors use GMP's assembly mpn_divrem_2 (on a shifted copy of the dividend) from FLINT_MPN_DIV_2_GMP_CUTOFF dividend limbs where it is faster.

Certifying a Newton quotient#

Newton division computes the quotient a/b as a fixed-point number with m integer limbs and two fraction limbs, with an error below 4B^{-2} in absolute value. If the first fraction limb f satisfies 2 \le f \le B - 2, the true quotient a/b lies strictly between the computed integer part q and q + 1, so q = \lfloor a/b \rfloor; then the remainder a - qb is less than b and can be computed from a low product of \mathit{bn} limbs. Otherwise (with probability about 4/B for random inputs) the candidate is corrected by O(1) steps using a full product.

The variants#

Example#

Examplempn_tdiv_qr_basic.cchecked by make checkdoc
#include <gmp.h>
#include <flint/flint.h>
#include <flint/mpn_extras.h>

int main(void)
{
    flint_rand_t state;
    mp_size_t an = 100, bn = 37, qn = an - bn + 1;
    mp_limb_t a[100], b[37], q[64], r[37], q2[64], r2[37], t[101];

    flint_rand_init(state);
    flint_mpn_urandomb(a, state, an * FLINT_BITS);
    flint_mpn_urandomb(b, state, bn * FLINT_BITS);
    b[bn - 1] |= 1;     /* nonzero top limb */

    flint_mpn_tdiv_qr(q, r, a, an, b, bn);

    /* compare with GMP */
    mpn_tdiv_qr(q2, r2, 0, a, an, b, bn);
    flint_printf("agrees with GMP: %d\n",
        mpn_cmp(q, q2, qn) == 0 && mpn_cmp(r, r2, bn) == 0);

    /* check a = q b + r and r < b */
    flint_mpn_mul(t, q, qn, b, bn);
    mpn_add(t, t, an + 1, r, bn);
    flint_printf("a = q b + r: %d, r < b: %d\n",
        mpn_cmp(t, a, an) == 0 && t[an] == 0, mpn_cmp(r, b, bn) < 0);

    /* approximate quotient: q or q + 1 */
    flint_mpn_divapprox(q2, a, an, b, bn);
    mpn_sub_n(q2, q2, q, qn);
    flint_printf("divapprox - tdiv_q <= 1: %d\n",
        q2[0] <= 1 && flint_mpn_zero_p(q2 + 1, qn - 1));

    flint_rand_clear(state);
    return 0;
}
Output
agrees with GMP: 1
a = q b + r: 1, r < b: 1
divapprox - tdiv_q <= 1: 1

References#

  • [GraMol2010] N. Möller and T. Granlund, "Improved division by invariant integers", IEEE Transactions on Computers 60 (2011), 165–175, https://gmplib.org/~tege/division-paper.pdf
  • [KM1997] A. H. Karp and P. Markstein, "High-precision division and square root", ACM Transactions on Mathematical Software 23:4 (1997), 561–589
  • [BurZie1998] C. Burnikel and J. Ziegler. Fast recursive division. Max-Planck-Institut für Informatik, Research Report MPI-I-98-1-022, 1998.
  • [HZ2011] D. Harvey and P. Zimmermann, "Short division of long integers" (2011), Proceedings of the 20th Symposium on Computer Arithmetic (ARITH-20), July 25-27, 2011, pages 7-14. https://web.maths.unsw.edu.au/~davidharvey/research/shortdiv.pdf
Cite this page

The FLINT team, “Euclidean division of limb arrays (mpn_extras.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/mpn_extras/tdiv_qr.html (generated 2026-10-20).