Blame gen-psqr.c

Packit 5c3484
/* Generate perfect square testing data.
Packit 5c3484
Packit 5c3484
Copyright 2002-2004, 2012, 2014 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include <stdlib.h>
Packit 5c3484
Packit 5c3484
#include "bootstrap.c"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* The aim of this program is to choose either mpn_mod_34lsub1 or mpn_mod_1
Packit 5c3484
   (plus a PERFSQR_PP modulus), and generate tables indicating quadratic
Packit 5c3484
   residues and non-residues modulo small factors of that modulus.
Packit 5c3484
Packit 5c3484
   For the usual 32 or 64 bit cases mpn_mod_34lsub1 gets used.  That
Packit 5c3484
   function exists specifically because 2^24-1 and 2^48-1 have nice sets of
Packit 5c3484
   prime factors.  For other limb sizes it's considered, but if it doesn't
Packit 5c3484
   have good factors then mpn_mod_1 will be used instead.
Packit 5c3484
Packit 5c3484
   When mpn_mod_1 is used, the modulus PERFSQR_PP is created from a
Packit 5c3484
   selection of small primes, chosen to fill PERFSQR_MOD_BITS of a limb,
Packit 5c3484
   with that bit count chosen so (2*GMP_LIMB_BITS)*2^PERFSQR_MOD_BITS <=
Packit 5c3484
   GMP_LIMB_MAX, allowing PERFSQR_MOD_IDX in mpn/generic/perfsqr.c to do its
Packit 5c3484
   calculation within a single limb.
Packit 5c3484
Packit 5c3484
   In either case primes can be combined to make divisors.  The table data
Packit 5c3484
   then effectively indicates remainders which are quadratic residues mod
Packit 5c3484
   all the primes.  This sort of combining reduces the number of steps
Packit 5c3484
   needed after mpn_mod_34lsub1 or mpn_mod_1, saving code size and time.
Packit 5c3484
   Nothing is gained or lost in terms of detections, the same total fraction
Packit 5c3484
   of non-residues will be identified.
Packit 5c3484
Packit 5c3484
   Nothing particularly sophisticated is attempted for combining factors to
Packit 5c3484
   make divisors.  This is probably a kind of knapsack problem so it'd be
Packit 5c3484
   too hard to attempt anything completely general.  For the usual 32 and 64
Packit 5c3484
   bit limbs we get a good enough result just pairing the biggest and
Packit 5c3484
   smallest which fit together, repeatedly.
Packit 5c3484
Packit 5c3484
   Another aim is to get powerful combinations, ie. divisors which identify
Packit 5c3484
   biggest fraction of non-residues, and have those run first.  Again for
Packit 5c3484
   the usual 32 and 64 bits it seems good enough just to pair for big
Packit 5c3484
   divisors then sort according to the resulting fraction of non-residues
Packit 5c3484
   identified.
Packit 5c3484
Packit 5c3484
   Also in this program, a table sq_res_0x100 of residues modulo 256 is
Packit 5c3484
   generated.  This simply fills bits into limbs of the appropriate
Packit 5c3484
   build-time GMP_LIMB_BITS each.
Packit 5c3484
Packit 5c3484
*/
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Normally we aren't using const in gen*.c programs, so as not to have to
Packit 5c3484
   bother figuring out if it works, but using it with f_cmp_divisor and
Packit 5c3484
   f_cmp_fraction avoids warnings from the qsort calls. */
Packit 5c3484
Packit 5c3484
/* Same tests as gmp.h. */
Packit 5c3484
#if  defined (__STDC__)                                 \
Packit 5c3484
  || defined (__cplusplus)                              \
Packit 5c3484
  || defined (_AIX)                                     \
Packit 5c3484
  || defined (__DECC)                                   \
Packit 5c3484
  || (defined (__mips) && defined (_SYSTYPE_SVR4))      \
Packit 5c3484
  || defined (_MSC_VER)                                 \
Packit 5c3484
  || defined (_WIN32)
Packit 5c3484
#define HAVE_CONST        1
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if ! HAVE_CONST
Packit 5c3484
#define const
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
Packit 5c3484
mpz_t  *sq_res_0x100;          /* table of limbs */
Packit 5c3484
int    nsq_res_0x100;          /* elements in sq_res_0x100 array */
Packit 5c3484
int    sq_res_0x100_num;       /* squares in sq_res_0x100 */
Packit 5c3484
double sq_res_0x100_fraction;  /* sq_res_0x100_num / 256 */
Packit 5c3484
Packit 5c3484
int     mod34_bits;        /* 3*GMP_NUMB_BITS/4 */
Packit 5c3484
int     mod_bits;          /* bits from PERFSQR_MOD_34 or MOD_PP */
Packit 5c3484
int     max_divisor;       /* all divisors <= max_divisor */
Packit 5c3484
int     max_divisor_bits;  /* ceil(log2(max_divisor)) */
Packit 5c3484
double  total_fraction;    /* of squares */
Packit 5c3484
mpz_t   pp;                /* product of primes, or 0 if mod_34lsub1 used */
Packit 5c3484
mpz_t   pp_norm;           /* pp shifted so NUMB high bit set */
Packit 5c3484
mpz_t   pp_inverted;       /* invert_limb style inverse */
Packit 5c3484
mpz_t   mod_mask;          /* 2^mod_bits-1 */
Packit 5c3484
char    mod34_excuse[128]; /* why mod_34lsub1 not used (if it's not) */
Packit 5c3484
Packit 5c3484
/* raw list of divisors of 2^mod34_bits-1 or pp, just to show in a comment */
Packit 5c3484
struct rawfactor_t {
Packit 5c3484
  int     divisor;
Packit 5c3484
  int     multiplicity;
Packit 5c3484
};
Packit 5c3484
struct rawfactor_t  *rawfactor;
Packit 5c3484
int                 nrawfactor;
Packit 5c3484
Packit 5c3484
/* factors of 2^mod34_bits-1 or pp and associated data, after combining etc */
Packit 5c3484
struct factor_t {
Packit 5c3484
  int     divisor;
Packit 5c3484
  mpz_t   inverse;   /* 1/divisor mod 2^mod_bits */
Packit 5c3484
  mpz_t   mask;      /* indicating squares mod divisor */
Packit 5c3484
  double  fraction;  /* squares/total */
Packit 5c3484
};
Packit 5c3484
struct factor_t  *factor;
Packit 5c3484
int              nfactor;       /* entries in use in factor array */
Packit 5c3484
int              factor_alloc;  /* entries allocated to factor array */
Packit 5c3484
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
f_cmp_divisor (const void *parg, const void *qarg)
Packit 5c3484
{
Packit 5c3484
  const struct factor_t *p, *q;
Packit 5c3484
  p = (const struct factor_t *) parg;
Packit 5c3484
  q = (const struct factor_t *) qarg;
Packit 5c3484
  if (p->divisor > q->divisor)
Packit 5c3484
    return 1;
Packit 5c3484
  else if (p->divisor < q->divisor)
Packit 5c3484
    return -1;
Packit 5c3484
  else
Packit 5c3484
    return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
f_cmp_fraction (const void *parg, const void *qarg)
Packit 5c3484
{
Packit 5c3484
  const struct factor_t *p, *q;
Packit 5c3484
  p = (const struct factor_t *) parg;
Packit 5c3484
  q = (const struct factor_t *) qarg;
Packit 5c3484
  if (p->fraction > q->fraction)
Packit 5c3484
    return 1;
Packit 5c3484
  else if (p->fraction < q->fraction)
Packit 5c3484
    return -1;
Packit 5c3484
  else
Packit 5c3484
    return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* Remove array[idx] by copying the remainder down, and adjust narray
Packit 5c3484
   accordingly.  */
Packit 5c3484
#define COLLAPSE_ELEMENT(array, idx, narray)                    \
Packit 5c3484
  do {                                                          \
Packit 5c3484
    memmove (&(array)[idx],					\
Packit 5c3484
	     &(array)[idx+1],					\
Packit 5c3484
	     ((narray)-((idx)+1)) * sizeof (array[0]));		\
Packit 5c3484
    (narray)--;                                                 \
Packit 5c3484
  } while (0)
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* return n*2^p mod m */
Packit 5c3484
int
Packit 5c3484
mul_2exp_mod (int n, int p, int m)
Packit 5c3484
{
Packit 5c3484
  while (--p >= 0)
Packit 5c3484
    n = (2 * n) % m;
Packit 5c3484
  return n;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* return -n mod m */
Packit 5c3484
int
Packit 5c3484
neg_mod (int n, int m)
Packit 5c3484
{
Packit 5c3484
  assert (n >= 0 && n < m);
Packit 5c3484
  return (n == 0 ? 0 : m-n);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* Set "mask" to a value such that "mask & (1<
Packit 5c3484
   "-(idx<
Packit 5c3484
void
Packit 5c3484
square_mask (mpz_t mask, int m)
Packit 5c3484
{
Packit 5c3484
  int    p, i, r, idx;
Packit 5c3484
Packit 5c3484
  p = mul_2exp_mod (1, mod_bits, m);
Packit 5c3484
  p = neg_mod (p, m);
Packit 5c3484
Packit 5c3484
  mpz_set_ui (mask, 0L);
Packit 5c3484
  for (i = 0; i < m; i++)
Packit 5c3484
    {
Packit 5c3484
      r = (i * i) % m;
Packit 5c3484
      idx = (r * p) % m;
Packit 5c3484
      mpz_setbit (mask, (unsigned long) idx);
Packit 5c3484
    }
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
generate_sq_res_0x100 (int limb_bits)
Packit 5c3484
{
Packit 5c3484
  int  i, res;
Packit 5c3484
Packit 5c3484
  nsq_res_0x100 = (0x100 + limb_bits - 1) / limb_bits;
Packit 5c3484
  sq_res_0x100 = (mpz_t *) xmalloc (nsq_res_0x100 * sizeof (*sq_res_0x100));
Packit 5c3484
Packit 5c3484
  for (i = 0; i < nsq_res_0x100; i++)
Packit 5c3484
    mpz_init_set_ui (sq_res_0x100[i], 0L);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < 0x100; i++)
Packit 5c3484
    {
Packit 5c3484
      res = (i * i) % 0x100;
Packit 5c3484
      mpz_setbit (sq_res_0x100[res / limb_bits],
Packit 5c3484
                  (unsigned long) (res % limb_bits));
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  sq_res_0x100_num = 0;
Packit 5c3484
  for (i = 0; i < nsq_res_0x100; i++)
Packit 5c3484
    sq_res_0x100_num += mpz_popcount (sq_res_0x100[i]);
Packit 5c3484
  sq_res_0x100_fraction = (double) sq_res_0x100_num / 256.0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
generate_mod (int limb_bits, int nail_bits)
Packit 5c3484
{
Packit 5c3484
  int    numb_bits = limb_bits - nail_bits;
Packit 5c3484
  int    i, divisor;
Packit 5c3484
Packit 5c3484
  mpz_init_set_ui (pp, 0L);
Packit 5c3484
  mpz_init_set_ui (pp_norm, 0L);
Packit 5c3484
  mpz_init_set_ui (pp_inverted, 0L);
Packit 5c3484
Packit 5c3484
  /* no more than limb_bits many factors in a one limb modulus (and of
Packit 5c3484
     course in reality nothing like that many) */
Packit 5c3484
  factor_alloc = limb_bits;
Packit 5c3484
  factor = (struct factor_t *) xmalloc (factor_alloc * sizeof (*factor));
Packit 5c3484
  rawfactor = (struct rawfactor_t *) xmalloc (factor_alloc * sizeof (*rawfactor));
Packit 5c3484
Packit 5c3484
  if (numb_bits % 4 != 0)
Packit 5c3484
    {
Packit 5c3484
      strcpy (mod34_excuse, "GMP_NUMB_BITS % 4 != 0");
Packit 5c3484
      goto use_pp;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  max_divisor = 2*limb_bits;
Packit 5c3484
  max_divisor_bits = log2_ceil (max_divisor);
Packit 5c3484
Packit 5c3484
  if (numb_bits / 4 < max_divisor_bits)
Packit 5c3484
    {
Packit 5c3484
      /* Wind back to one limb worth of max_divisor, if that will let us use
Packit 5c3484
         mpn_mod_34lsub1.  */
Packit 5c3484
      max_divisor = limb_bits;
Packit 5c3484
      max_divisor_bits = log2_ceil (max_divisor);
Packit 5c3484
Packit 5c3484
      if (numb_bits / 4 < max_divisor_bits)
Packit 5c3484
        {
Packit 5c3484
          strcpy (mod34_excuse, "GMP_NUMB_BITS / 4 too small");
Packit 5c3484
          goto use_pp;
Packit 5c3484
        }
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  {
Packit 5c3484
    /* Can use mpn_mod_34lsub1, find small factors of 2^mod34_bits-1. */
Packit 5c3484
    mpz_t  m, q, r;
Packit 5c3484
    int    multiplicity;
Packit 5c3484
Packit 5c3484
    mod34_bits = (numb_bits / 4) * 3;
Packit 5c3484
Packit 5c3484
    /* mpn_mod_34lsub1 returns a full limb value, PERFSQR_MOD_34 folds it at
Packit 5c3484
       the mod34_bits mark, adding the two halves for a remainder of at most
Packit 5c3484
       mod34_bits+1 many bits */
Packit 5c3484
    mod_bits = mod34_bits + 1;
Packit 5c3484
Packit 5c3484
    mpz_init_set_ui (m, 1L);
Packit 5c3484
    mpz_mul_2exp (m, m, mod34_bits);
Packit 5c3484
    mpz_sub_ui (m, m, 1L);
Packit 5c3484
Packit 5c3484
    mpz_init (q);
Packit 5c3484
    mpz_init (r);
Packit 5c3484
Packit 5c3484
    for (i = 3; i <= max_divisor; i+=2)
Packit 5c3484
      {
Packit 5c3484
        if (! isprime (i))
Packit 5c3484
          continue;
Packit 5c3484
Packit 5c3484
        mpz_tdiv_qr_ui (q, r, m, (unsigned long) i);
Packit 5c3484
        if (mpz_sgn (r) != 0)
Packit 5c3484
          continue;
Packit 5c3484
Packit 5c3484
        /* if a repeated prime is found it's used as an i^n in one factor */
Packit 5c3484
        divisor = 1;
Packit 5c3484
        multiplicity = 0;
Packit 5c3484
        do
Packit 5c3484
          {
Packit 5c3484
            if (divisor > max_divisor / i)
Packit 5c3484
              break;
Packit 5c3484
            multiplicity++;
Packit 5c3484
            mpz_set (m, q);
Packit 5c3484
            mpz_tdiv_qr_ui (q, r, m, (unsigned long) i);
Packit 5c3484
          }
Packit 5c3484
        while (mpz_sgn (r) == 0);
Packit 5c3484
Packit 5c3484
        assert (nrawfactor < factor_alloc);
Packit 5c3484
        rawfactor[nrawfactor].divisor = i;
Packit 5c3484
        rawfactor[nrawfactor].multiplicity = multiplicity;
Packit 5c3484
        nrawfactor++;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    mpz_clear (m);
Packit 5c3484
    mpz_clear (q);
Packit 5c3484
    mpz_clear (r);
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
  if (nrawfactor <= 2)
Packit 5c3484
    {
Packit 5c3484
      mpz_t  new_pp;
Packit 5c3484
Packit 5c3484
      sprintf (mod34_excuse, "only %d small factor%s",
Packit 5c3484
               nrawfactor, nrawfactor == 1 ? "" : "s");
Packit 5c3484
Packit 5c3484
    use_pp:
Packit 5c3484
      /* reset to two limbs of max_divisor, in case the mpn_mod_34lsub1 code
Packit 5c3484
         tried with just one */
Packit 5c3484
      max_divisor = 2*limb_bits;
Packit 5c3484
      max_divisor_bits = log2_ceil (max_divisor);
Packit 5c3484
Packit 5c3484
      mpz_init (new_pp);
Packit 5c3484
      nrawfactor = 0;
Packit 5c3484
      mod_bits = MIN (numb_bits, limb_bits - max_divisor_bits);
Packit 5c3484
Packit 5c3484
      /* one copy of each small prime */
Packit 5c3484
      mpz_set_ui (pp, 1L);
Packit 5c3484
      for (i = 3; i <= max_divisor; i+=2)
Packit 5c3484
        {
Packit 5c3484
          if (! isprime (i))
Packit 5c3484
            continue;
Packit 5c3484
Packit 5c3484
          mpz_mul_ui (new_pp, pp, (unsigned long) i);
Packit 5c3484
          if (mpz_sizeinbase (new_pp, 2) > mod_bits)
Packit 5c3484
            break;
Packit 5c3484
          mpz_set (pp, new_pp);
Packit 5c3484
Packit 5c3484
          assert (nrawfactor < factor_alloc);
Packit 5c3484
          rawfactor[nrawfactor].divisor = i;
Packit 5c3484
          rawfactor[nrawfactor].multiplicity = 1;
Packit 5c3484
          nrawfactor++;
Packit 5c3484
        }
Packit 5c3484
Packit 5c3484
      /* Plus an extra copy of one or more of the primes selected, if that
Packit 5c3484
         still fits in max_divisor and the total in mod_bits.  Usually only
Packit 5c3484
         3 or 5 will be candidates */
Packit 5c3484
      for (i = nrawfactor-1; i >= 0; i--)
Packit 5c3484
        {
Packit 5c3484
          if (rawfactor[i].divisor > max_divisor / rawfactor[i].divisor)
Packit 5c3484
            continue;
Packit 5c3484
          mpz_mul_ui (new_pp, pp, (unsigned long) rawfactor[i].divisor);
Packit 5c3484
          if (mpz_sizeinbase (new_pp, 2) > mod_bits)
Packit 5c3484
            continue;
Packit 5c3484
          mpz_set (pp, new_pp);
Packit 5c3484
Packit 5c3484
          rawfactor[i].multiplicity++;
Packit 5c3484
        }
Packit 5c3484
Packit 5c3484
      mod_bits = mpz_sizeinbase (pp, 2);
Packit 5c3484
Packit 5c3484
      mpz_set (pp_norm, pp);
Packit 5c3484
      while (mpz_sizeinbase (pp_norm, 2) < numb_bits)
Packit 5c3484
        mpz_add (pp_norm, pp_norm, pp_norm);
Packit 5c3484
Packit 5c3484
      mpz_preinv_invert (pp_inverted, pp_norm, numb_bits);
Packit 5c3484
Packit 5c3484
      mpz_clear (new_pp);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* start the factor array */
Packit 5c3484
  for (i = 0; i < nrawfactor; i++)
Packit 5c3484
    {
Packit 5c3484
      int  j;
Packit 5c3484
      assert (nfactor < factor_alloc);
Packit 5c3484
      factor[nfactor].divisor = 1;
Packit 5c3484
      for (j = 0; j < rawfactor[i].multiplicity; j++)
Packit 5c3484
        factor[nfactor].divisor *= rawfactor[i].divisor;
Packit 5c3484
      nfactor++;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
 combine:
Packit 5c3484
  /* Combine entries in the factor array.  Combine the smallest entry with
Packit 5c3484
     the biggest one that will fit with it (ie. under max_divisor), then
Packit 5c3484
     repeat that with the new smallest entry. */
Packit 5c3484
  qsort (factor, nfactor, sizeof (factor[0]), f_cmp_divisor);
Packit 5c3484
  for (i = nfactor-1; i >= 1; i--)
Packit 5c3484
    {
Packit 5c3484
      if (factor[i].divisor <= max_divisor / factor[0].divisor)
Packit 5c3484
        {
Packit 5c3484
          factor[0].divisor *= factor[i].divisor;
Packit 5c3484
          COLLAPSE_ELEMENT (factor, i, nfactor);
Packit 5c3484
          goto combine;
Packit 5c3484
        }
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  total_fraction = 1.0;
Packit 5c3484
  for (i = 0; i < nfactor; i++)
Packit 5c3484
    {
Packit 5c3484
      mpz_init (factor[i].inverse);
Packit 5c3484
      mpz_invert_ui_2exp (factor[i].inverse,
Packit 5c3484
                          (unsigned long) factor[i].divisor,
Packit 5c3484
                          (unsigned long) mod_bits);
Packit 5c3484
Packit 5c3484
      mpz_init (factor[i].mask);
Packit 5c3484
      square_mask (factor[i].mask, factor[i].divisor);
Packit 5c3484
Packit 5c3484
      /* fraction of possible squares */
Packit 5c3484
      factor[i].fraction = (double) mpz_popcount (factor[i].mask)
Packit 5c3484
        / factor[i].divisor;
Packit 5c3484
Packit 5c3484
      /* total fraction of possible squares */
Packit 5c3484
      total_fraction *= factor[i].fraction;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* best tests first (ie. smallest fraction) */
Packit 5c3484
  qsort (factor, nfactor, sizeof (factor[0]), f_cmp_fraction);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
print (int limb_bits, int nail_bits)
Packit 5c3484
{
Packit 5c3484
  int    i;
Packit 5c3484
  mpz_t  mhi, mlo;
Packit 5c3484
Packit 5c3484
  printf ("/* This file generated by gen-psqr.c - DO NOT EDIT. */\n");
Packit 5c3484
  printf ("\n");
Packit 5c3484
Packit 5c3484
  printf ("#if GMP_LIMB_BITS != %d || GMP_NAIL_BITS != %d\n",
Packit 5c3484
          limb_bits, nail_bits);
Packit 5c3484
  printf ("Error, error, this data is for %d bit limb and %d bit nail\n",
Packit 5c3484
          limb_bits, nail_bits);
Packit 5c3484
  printf ("#endif\n");
Packit 5c3484
  printf ("\n");
Packit 5c3484
Packit 5c3484
  printf ("/* Non-zero bit indicates a quadratic residue mod 0x100.\n");
Packit 5c3484
  printf ("   This test identifies %.2f%% as non-squares (%d/256). */\n",
Packit 5c3484
          (1.0 - sq_res_0x100_fraction) * 100.0,
Packit 5c3484
          0x100 - sq_res_0x100_num);
Packit 5c3484
  printf ("static const mp_limb_t\n");
Packit 5c3484
  printf ("sq_res_0x100[%d] = {\n", nsq_res_0x100);
Packit 5c3484
  for (i = 0; i < nsq_res_0x100; i++)
Packit 5c3484
    {
Packit 5c3484
      printf ("  CNST_LIMB(0x");
Packit 5c3484
      mpz_out_str (stdout, 16, sq_res_0x100[i]);
Packit 5c3484
      printf ("),\n");
Packit 5c3484
    }
Packit 5c3484
  printf ("};\n");
Packit 5c3484
  printf ("\n");
Packit 5c3484
Packit 5c3484
  if (mpz_sgn (pp) != 0)
Packit 5c3484
    {
Packit 5c3484
      printf ("/* mpn_mod_34lsub1 not used due to %s */\n", mod34_excuse);
Packit 5c3484
      printf ("/* PERFSQR_PP = ");
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    printf ("/* 2^%d-1 = ", mod34_bits);
Packit 5c3484
  for (i = 0; i < nrawfactor; i++)
Packit 5c3484
    {
Packit 5c3484
      if (i != 0)
Packit 5c3484
        printf (" * ");
Packit 5c3484
      printf ("%d", rawfactor[i].divisor);
Packit 5c3484
      if (rawfactor[i].multiplicity != 1)
Packit 5c3484
        printf ("^%d", rawfactor[i].multiplicity);
Packit 5c3484
    }
Packit 5c3484
  printf (" %s*/\n", mpz_sgn (pp) == 0 ? "... " : "");
Packit 5c3484
Packit 5c3484
  printf ("#define PERFSQR_MOD_BITS  %d\n", mod_bits);
Packit 5c3484
  if (mpz_sgn (pp) != 0)
Packit 5c3484
    {
Packit 5c3484
      printf ("#define PERFSQR_PP            CNST_LIMB(0x");
Packit 5c3484
      mpz_out_str (stdout, 16, pp);
Packit 5c3484
      printf (")\n");
Packit 5c3484
      printf ("#define PERFSQR_PP_NORM       CNST_LIMB(0x");
Packit 5c3484
      mpz_out_str (stdout, 16, pp_norm);
Packit 5c3484
      printf (")\n");
Packit 5c3484
      printf ("#define PERFSQR_PP_INVERTED   CNST_LIMB(0x");
Packit 5c3484
      mpz_out_str (stdout, 16, pp_inverted);
Packit 5c3484
      printf (")\n");
Packit 5c3484
    }
Packit 5c3484
  printf ("\n");
Packit 5c3484
Packit 5c3484
  mpz_init (mhi);
Packit 5c3484
  mpz_init (mlo);
Packit 5c3484
Packit 5c3484
  printf ("/* This test identifies %.2f%% as non-squares. */\n",
Packit 5c3484
          (1.0 - total_fraction) * 100.0);
Packit 5c3484
  printf ("#define PERFSQR_MOD_TEST(up, usize) \\\n");
Packit 5c3484
  printf ("  do {                              \\\n");
Packit 5c3484
  printf ("    mp_limb_t  r;                   \\\n");
Packit 5c3484
  if (mpz_sgn (pp) != 0)
Packit 5c3484
    printf ("    PERFSQR_MOD_PP (r, up, usize);  \\\n");
Packit 5c3484
  else
Packit 5c3484
    printf ("    PERFSQR_MOD_34 (r, up, usize);  \\\n");
Packit 5c3484
Packit 5c3484
  for (i = 0; i < nfactor; i++)
Packit 5c3484
    {
Packit 5c3484
      printf ("                                    \\\n");
Packit 5c3484
      printf ("    /* %5.2f%% */                    \\\n",
Packit 5c3484
              (1.0 - factor[i].fraction) * 100.0);
Packit 5c3484
Packit 5c3484
      printf ("    PERFSQR_MOD_%d (r, CNST_LIMB(%2d), CNST_LIMB(0x",
Packit 5c3484
              factor[i].divisor <= limb_bits ? 1 : 2,
Packit 5c3484
              factor[i].divisor);
Packit 5c3484
      mpz_out_str (stdout, 16, factor[i].inverse);
Packit 5c3484
      printf ("), \\\n");
Packit 5c3484
      printf ("                   CNST_LIMB(0x");
Packit 5c3484
Packit 5c3484
      if ( factor[i].divisor <= limb_bits)
Packit 5c3484
        {
Packit 5c3484
          mpz_out_str (stdout, 16, factor[i].mask);
Packit 5c3484
        }
Packit 5c3484
      else
Packit 5c3484
        {
Packit 5c3484
          mpz_tdiv_r_2exp (mlo, factor[i].mask, (unsigned long) limb_bits);
Packit 5c3484
          mpz_tdiv_q_2exp (mhi, factor[i].mask, (unsigned long) limb_bits);
Packit 5c3484
          mpz_out_str (stdout, 16, mhi);
Packit 5c3484
          printf ("), CNST_LIMB(0x");
Packit 5c3484
          mpz_out_str (stdout, 16, mlo);
Packit 5c3484
        }
Packit 5c3484
      printf (")); \\\n");
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  printf ("  } while (0)\n");
Packit 5c3484
  printf ("\n");
Packit 5c3484
Packit 5c3484
  printf ("/* Grand total sq_res_0x100 and PERFSQR_MOD_TEST, %.2f%% non-squares. */\n",
Packit 5c3484
          (1.0 - (total_fraction * 44.0/256.0)) * 100.0);
Packit 5c3484
  printf ("\n");
Packit 5c3484
Packit 5c3484
  printf ("/* helper for tests/mpz/t-perfsqr.c */\n");
Packit 5c3484
  printf ("#define PERFSQR_DIVISORS  { 256,");
Packit 5c3484
  for (i = 0; i < nfactor; i++)
Packit 5c3484
      printf (" %d,", factor[i].divisor);
Packit 5c3484
  printf (" }\n");
Packit 5c3484
Packit 5c3484
Packit 5c3484
  mpz_clear (mhi);
Packit 5c3484
  mpz_clear (mlo);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
main (int argc, char *argv[])
Packit 5c3484
{
Packit 5c3484
  int  limb_bits, nail_bits;
Packit 5c3484
Packit 5c3484
  if (argc != 3)
Packit 5c3484
    {
Packit 5c3484
      fprintf (stderr, "Usage: gen-psqr <limbbits> <nailbits>\n");
Packit 5c3484
      exit (1);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  limb_bits = atoi (argv[1]);
Packit 5c3484
  nail_bits = atoi (argv[2]);
Packit 5c3484
Packit 5c3484
  if (limb_bits <= 0
Packit 5c3484
      || nail_bits < 0
Packit 5c3484
      || nail_bits >= limb_bits)
Packit 5c3484
    {
Packit 5c3484
      fprintf (stderr, "Invalid limb/nail bits: %d %d\n",
Packit 5c3484
               limb_bits, nail_bits);
Packit 5c3484
      exit (1);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  generate_sq_res_0x100 (limb_bits);
Packit 5c3484
  generate_mod (limb_bits, nail_bits);
Packit 5c3484
Packit 5c3484
  print (limb_bits, nail_bits);
Packit 5c3484
Packit 5c3484
  return 0;
Packit 5c3484
}