flint_mpn division, square roots and powers - #2834
Merged
Merged
Conversation
This was referenced Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
flint_mpn_*functions for division, square root, etc. and uses these infmpz,arfand elsewhere. GMP is used for small sizes, Newton iteration based onflint_mpn_mul*for huge input (replacing old inefficientarf-based Newton code).Implemented mostly using Claude Fable 5.1.
@albinahlback The interfaces are now in place for inserting faster basecase division code :-)
In passing this fixes #2317:
fmpz_ndiv_qrdeliberately changes tiebreaking to even. This breaks a Nemo test, which has to be updated downstream.New public functions
mpn_extras— Hensel (2-adic) arithmeticflint_mpn_binvx^-1 mod B^nfor oddxflint_mpn_bdiv_qrnquotient limbs, optional remainderflint_mpn_bdiv_qflint_mpn_bdiv_qr_1flint_mpn_bdiv_qr_classicalflint_mpn_bdiv_qr_karp_marksteinflint_mpn_brsqrtflint_mpn_bsqrt_flint_mpn_mulhigh_known_low_flint_mpn_bdiv_qr_classical_preinvmpn_extras— Euclidean divisionflint_mpn_tdiv_qr,flint_mpn_tdiv_q,flint_mpn_tdiv_rflint_mpn_cdiv_qr,flint_mpn_cdiv_q,flint_mpn_cdiv_rflint_mpn_ndiv_qr,flint_mpn_ndiv_q,flint_mpn_ndiv_rflint_mpn_divflint_mpn_divexactflint_mpn_divisibleflint_mpn_invfloor(B^n / x)_flint_mpn_tdiv_qrand_newton,_unbalanced,_preinv,_preinvn,_gmp_flint_mpn_divexact,_flint_mpn_divexact_hensel,_flint_mpn_divisibleflint_mpn_divexact_preinv_init/_clear/flint_mpn_divexact_preinvflint_mpn_divexact_preinv_t)mpn_extras— square root, powering, miscflint_mpn_sqrtremr == NULLreturns 0 iff a perfect squareflint_mpn_sqrtflint_mpn_is_square_flint_mpn_sqrtrem,_flint_mpn_sqrtrem_newton,_flint_mpn_sqrtrem_gmp,_flint_mpn_sqrt,_flint_mpn_is_squareflint_mpn_pow,flint_mpn_pow_bound_limbsflint_mpn_mod_2exp48m12^48 - 1(AVX2 kernel; 64-bit only)mpn_extras— mpz-like interfaceIntermediate wrappers used by the
fmpzlayer; if there is interest we could promote these to anmpz_extrasmodule in the future.flint_mpz_tdiv_qr,_tdiv_q,_tdiv_r,flint_mpz_fdiv_qr,_fdiv_q,_fdiv_r,flint_mpz_cdiv_qr,_cdiv_q,_cdiv_r,flint_mpz_mod,flint_mpz_divexact,flint_mpz_sqrt,flint_mpz_sqrtrem(inline dispatch;_flint_mpz_*backends).fmpzfmpz_div,fmpz_div_ui,fmpz_div_sifmpz_dividesis now an alias offmpz_div)fmpz_perfect_sqrtfmpz_invmod_2exp2^Nfmpz_sqrtmod_2exp,fmpz_rsqrtmod_2expfmpz_divmod_2exp2^NarfARF_RND_FAST,ARF_RND_ACCURATEarf_rnd_relaxed_to_strict_arf_inv_newton,_arf_div_newton,_arf_sqrt_newton,_arf_rsqrt_newton_arf_want_newton_inv/div/sqrt/rsqrt(inline) and_largevariantsChanged behaviour of existing functions
fmpz_ndiv_qrfmpz_dividesfmpz_divfmpz_tdiv_q/qr,fdiv_q/qr/r,cdiv_q/qr,fmpz_mod,fmpz_divexactfmpz_tdiv_q_si/ui,fdiv_q_si/ui,cdiv_q_si/ui,divexact_si/ui,tdiv_ui,fdiv_ui,cdiv_uifmpz_sqrt,fmpz_sqrtremfmpz_is_squarefmpz_pow_uiflint_mpn_powarf_div,arf_ui_div,arf_sqrt,arf_rsqrt(andarf_div_ui/si/fmpz,arf_fmpz_div_fmpz, …)arf_set_round/_arf_set_round_mpnarf_divflint_mpn_tdiv_qinstead of__gmpn_div_qarb_div,arb_div_arf,arb_div_fmpz,arb_sqrt,arb_sqrt_arf,arb_rsqrt,arb_rsqrt_arfARF_RND_FAST; all Newton machinery removedflint_mpn_preinvnflint_mpn_invflint_mpn_divides_flint_mpn_tdiv_qrmpn_tdiv_q(compat shim)mpn_div_q_fmpz_vec_scalar_divexact_fmpz,fmpz_mat_scalar_divexact_fmpz_padic_inv,_padic_sqrtp = 2cases usefmpz_invmod_2exp/fmpz_sqrtmod_2expfmpz_poly_sqrt_KS,fmpz_mpoly_sqrt_heap,mpn_extras/multi_mod,multi_crt,multi_crt_oncegrfmpzringsqrtviafmpz_perfect_sqrt,divviafmpz_div, newdiv_ui/div_simethodsradix_sqrtrem_newton_karp_marksteinRemoved
arb_div_newton,arb_div_arf_newton,_arb_fmpz_divapprox_newton,arb_fmpz_divapprox,arb_sqrt_newton,arb_sqrt_arf_newton,arb_rsqrt_arf_newton, the_fmpz_*_newtonhooks andMPZ_WANT_FLINT_DIVISION(plus testst-div_newton.c,t-sqrt_newton.cin
arb,t-div_newton.cinfmpz).Build system
configure.acprobes__gmpn_divexact,__gmpn_mod_34lsub1,__gmpn_divisible_p(FLINT_HAVE_NATIVE_mpn_*).flint-mparam.hfiles defineFLINT_MPN_TDIV_QR_NEWTON_CUTOFF,FLINT_MPN_DIVEXACT_NEWTON_CUTOFF,FLINT_MPN_SQRTREM_NEWTON_CUTOFF.Performance
This mostly speeds up arithmetic with huge numbers.
I have tried very hard to ensure that there are no major regressions for small or unbalanced inputs. Unfortunately, due to the number of functions touched, it is possible that I've missed some spots. There are also some improvements for small input. For example:
flint_mpn_sqrtremhas 1- and 2-limb code which beats GMPfmpzdivision functions for 2-limb by 1-limb division and square root functions for 2-limb input have been optimized: they now compute the result in registers and write a small result without an unnecessary promote-demote cycleKnown regressions:
arf_div/arb_divandarf_sqrt/arb_sqrtare 3-4 nanoseconds slower than before, which is significant at 64-256 bits of precision (~5-10% overhead). I couldn't figure out how to fix this easily. However, the code is suboptimal here to begin with here, and I think a future rewrite of the division for low precision will give a speedup that is much bigger than the current regression.Ceiling division is slightly slower than before at high precision as it doesn't use the quotient-only path
Benchmarks:
fmpzvsmpzInput:
arandom with 2n bits,brandom with n bits,b2 = b^2. Each entry is the ratio time(mpz) / time(fmpz), so higher is better and values below 1.00 mean thefmpzfunction is slower than its GMP counterpart. The speedup columns are new/old, i.e. the improvement this PR gives over the current main branch.fmpz_tdiv_q— truncating quotienttdiv_q(q, a, b)for the inexact case,tdiv_q(q, b2, b)for the exact case (remainder 0).fmpz_cdiv_q— ceiling quotientfmpz_tdiv_qr— truncating quotient and remainderfmpz_divexact— exact divisionOnly the exact case exists:
divexact(q, b2, b).fmpz_divisible— divisibility testdivisible(a, b)for the negative case,divisible(b2, b)for the positive case.fmpz_sqrtrem— square root with remaindersqrtrem(s, r, a)for a generic (non-square) input,sqrtrem(s, r, b2)for a perfect square.fmpz_is_square— perfect square testis_square(a)for a generic (non-square) input,is_square(b2)for a perfect square.Note: the speedup here depends on the distribution of inputs. The lone 78x speedup in the table is for a set of input where the FLINT's residue screen happened to reject all random inputs while GMP's didn't.