mpz_sqrt_if_perfect_square

Niels Möller nisse at lysator.liu.se
Tue Jun 2 16:53:51 CEST 2026


Seth Troisi <braintwo at gmail.com> writes:

> I'm doing some prime gap searching which would slightly benefit from
> knowing the root of a number iff it's a perfect square.
...
> I coded up a working implementation for myself. I can work on making it
> clean enough for upstream if it's a desired feature.

Makes sense to me. Below a few initial comments after a quick first look.

> + at deftypefun int mpz_perfect_square (mpz_t @var{rop}, const mpz_t @var{op})
> + at cindex Perfect square functions
> + at cindex Root testing functions
> +Return non-zero and sets @var{rop} to the square root if @var{op} is a perfect
> +square, i.e., if the square root of @var{op} is an integer.  Under this
> +definition both 0 and 1 are considered to be perfect squares and @var{rop} is
> +set to @var{op} in both cases. If @var{op} is not a perfect square the value of
> + at var{rop} is undefined.
> + at end deftypefun

Would it be difficult to arrange so rop is unchanged in the case that
input is not a square? "undefined" is a bit scary.

> + at deftypefun int mpn_perfect_square (mp_limb_t *@var{r1p}, const mp_limb_t *@var{s1p}, mp_size_t @var{n})
> +Return non-zero iff @{@var{s1p}, @var{n}@} is a perfect square.
> +iff @{@var{s1p}, @var{n}@} is a perfect square @{@var{r1p}, @math{@GMPceil{@var{n} / 2}}@}
> +will be set to the square root.
> +The most significant limb of @{@var{s1p}, @var{n}@} must be non-zero.
> +The areas at @var{r1p} and @var{s1p} must be completely separate.
>  @end deftypefun

Would be good to document if output area is unchanged or clobbered in
the non-square case. Clobbered would be fine for an mpn function, but
unchanged would likely be helpful if we want "unchanged" for the mpz
function.

> +    {
> +      /* Iff mpn_sqrtrem returns zero, the square is perfect.  */
> +      int res = ! mpn_sqrtrem (rp, NULL, up, usize);
> +      return res;
> +    }

Would be nice to either move declaration of res and the return statement out
of the two if blocks, or write this simply as

  return ! mpn_sqrtrem (rp, NULL, up, usize);.

> +  int rop_size = (SIZ (u) + 1) / 2;
> +  if (SIZ(rop) < rop_size)
> +    {
> +      MPZ_REALLOC(rop, rop_size);
> +    }
> +
> +  res = mpn_perfect_square (PTR(rop), PTR (u), u_size);

If I understand the internal apis correctly, this can be simplified to

  res = mpn_perfect_square (MPZ_REALLOC(rop, rop_size), PTR (u), u_size);

> +  if (res)
> +    {
> +      SIZ(rop) = rop_size;

The top limb could be zero, right? Then a normalization step is needed
here. If it is guaranteed that at most one top limb is zero, something
like

         rop_size -= PTR(rop)[rop_size-1] == 0;

Regards,
/Niels

-- 
Niels Möller. PGP key CB4962D070D77D7FCB8BA36271D8F1FF368C6677.
Internet email is subject to wholesale government surveillance.


More information about the gmp-devel mailing list