Search code examples
c++cbigintegergmpinteger-division

Division using GMP's low-level API


I'm using GMP's low-level interface (mpn_, see https://gmplib.org/manual/Low_002dlevel-Functions) to do some fixed-size 192 bit (three limb) integer calculations.

Currently I am trying to divide one random uint192 by another random uint192 and fail to select the right function. There are multiple candidates:

  • mpn_tdiv_qr - Documentation says "most significant limb of the divisor must be non-zero"
  • mpn_divrem - Documentation says "obsolete"
  • mpn_divrem_1 - Takes a single limb as a divisor
  • mpn_divexact_1 - Documentation says "expecting ... to divide exactly"

So there is an obsolete function (mpn_divrem), a function that takes small (<= 64bit) divisors only (mpn_divrem_1), one that has undefined behavior with remainders (mpn_divexact_1) and one that takes large (>= 129bit) divisors only (mpn_tdiv_qr).

I tried mpn_tdiv_qr since I thought I'm misunderstanding the documentation and because it replaces the obsolete function. But it actually crashes when most significant limb is zero.

Did I miss something? How can I divide two random 3-limb-numbers? Or numbers with a divisor of 65..128 non-zero bits (e.g. 0xffffffff'ffffffffffffffff'ffffffffffffffff / 0xff'ffffffffffffffff)?


Solution

  • Ok, solution is simple: Instead of passing the number of allocated limbs to mpn_tdiv_qr pass the number of limbs minus the number of leading zero limbs of the divisor instead. E.g. when using 3 limbs and a concrete divisor has limb[2] == 0, limb[1] != 0 and limb[0] == 0 a 2 is passed for the divisor length. This way it is guaranteed that the most significant limb (in this case [1]) is non-zero.