Blame gen-trialdivtab.c

Packit 5c3484
/* gen-trialdivtab.c
Packit 5c3484
Packit 5c3484
   Contributed to the GNU project by Torbjorn Granlund.
Packit 5c3484
Packit 5c3484
Copyright 2009, 2012, 2013 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
/*
Packit 5c3484
  Generate tables for fast, division-free trial division for GMP.
Packit 5c3484
Packit 5c3484
  There is one main table, ptab.  It contains primes, multiplied together, and
Packit 5c3484
  several types of pre-computed inverses.  It refers to tables of the type
Packit 5c3484
  dtab, via the last two indices.  That table contains the individual primes in
Packit 5c3484
  the range, except that the primes are not actually included in the table (see
Packit 5c3484
  the P macro; it sneakingly excludes the primes themselves).  Instead, the
Packit 5c3484
  dtab tables contains tuples for each prime (modular-inverse, limit) used for
Packit 5c3484
  divisibility checks.
Packit 5c3484
Packit 5c3484
  This interface is not intended for division of very many primes, since then
Packit 5c3484
  other algorithms apply.
Packit 5c3484
*/
Packit 5c3484
Packit 5c3484
#include <stdlib.h>
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include "bootstrap.c"
Packit 5c3484
Packit 5c3484
int sumspills (mpz_t, mpz_t *, int);
Packit 5c3484
void mpn_mod_1s_4p_cps (mpz_t [7], mpz_t);
Packit 5c3484
Packit 5c3484
int limb_bits;
Packit 5c3484
Packit 5c3484
mpz_t B;
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
main (int argc, char *argv[])
Packit 5c3484
{
Packit 5c3484
  unsigned long t, p;
Packit 5c3484
  mpz_t ppp, acc, inv, gmp_numb_max, tmp, Bhalf;
Packit 5c3484
  mpz_t pre[7];
Packit 5c3484
  int i;
Packit 5c3484
  int start_p, end_p, interval_start, interval_end, omitted_p;
Packit 5c3484
  const char *endtok;
Packit 5c3484
  int stop;
Packit 5c3484
  int np, start_idx;
Packit 5c3484
Packit 5c3484
  if (argc < 2)
Packit 5c3484
    {
Packit 5c3484
      fprintf (stderr, "usage: %s bits endprime\n", argv[0]);
Packit 5c3484
      exit (1);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  limb_bits = atoi (argv[1]);
Packit 5c3484
Packit 5c3484
  end_p = 1290;			/* default end prime */
Packit 5c3484
  if (argc == 3)
Packit 5c3484
    end_p = atoi (argv[2]);
Packit 5c3484
Packit 5c3484
  printf ("#if GMP_LIMB_BITS != %d\n", limb_bits);
Packit 5c3484
  printf ("#error This table is for GMP_LIMB_BITS = %d\n", limb_bits);
Packit 5c3484
  printf ("#endif\n\n");
Packit 5c3484
Packit 5c3484
  printf ("#if GMP_NAIL_BITS != 0\n");
Packit 5c3484
  printf ("#error This table does not support nails\n");
Packit 5c3484
  printf ("#endif\n\n");
Packit 5c3484
Packit 5c3484
  for (i = 0; i < 7; i++)
Packit 5c3484
    mpz_init (pre[i]);
Packit 5c3484
Packit 5c3484
  mpz_init_set_ui (gmp_numb_max, 1);
Packit 5c3484
  mpz_mul_2exp (gmp_numb_max, gmp_numb_max, limb_bits);
Packit 5c3484
  mpz_sub_ui (gmp_numb_max, gmp_numb_max, 1);
Packit 5c3484
Packit 5c3484
  mpz_init (tmp);
Packit 5c3484
  mpz_init (inv);
Packit 5c3484
Packit 5c3484
  mpz_init_set_ui (B, 1);  mpz_mul_2exp (B, B, limb_bits);
Packit 5c3484
  mpz_init_set_ui (Bhalf, 1);  mpz_mul_2exp (Bhalf, Bhalf, limb_bits - 1);
Packit 5c3484
Packit 5c3484
  start_p = 3;
Packit 5c3484
Packit 5c3484
  mpz_init_set_ui (ppp, 1);
Packit 5c3484
  mpz_init (acc);
Packit 5c3484
  interval_start = start_p;
Packit 5c3484
  omitted_p = 3;
Packit 5c3484
  interval_end = 0;
Packit 5c3484
Packit 5c3484
/*  printf ("static struct gmp_primes_dtab gmp_primes_dtab[] = {\n"); */
Packit 5c3484
Packit 5c3484
  printf ("#ifdef WANT_dtab\n");
Packit 5c3484
Packit 5c3484
  for (t = start_p; t <= end_p; t += 2)
Packit 5c3484
    {
Packit 5c3484
      if (! isprime (t))
Packit 5c3484
	continue;
Packit 5c3484
Packit 5c3484
      mpz_mul_ui (acc, ppp, t);
Packit 5c3484
      stop = mpz_cmp (acc, Bhalf) >= 0;
Packit 5c3484
      if (!stop)
Packit 5c3484
	{
Packit 5c3484
	  mpn_mod_1s_4p_cps (pre, acc);
Packit 5c3484
	  stop = sumspills (acc, pre + 2, 5);
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (stop)
Packit 5c3484
	{
Packit 5c3484
	  for (p = interval_start; p <= interval_end; p += 2)
Packit 5c3484
	    {
Packit 5c3484
	      if (! isprime (p))
Packit 5c3484
		continue;
Packit 5c3484
Packit 5c3484
	      printf ("  P(%d,", (int) p);
Packit 5c3484
	      mpz_invert_ui_2exp (inv, p, limb_bits);
Packit 5c3484
	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, inv);  printf ("),");
Packit 5c3484
Packit 5c3484
	      mpz_tdiv_q_ui (tmp, gmp_numb_max, p);
Packit 5c3484
	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, tmp);
Packit 5c3484
	      printf (")),\n");
Packit 5c3484
	    }
Packit 5c3484
	  mpz_set_ui (ppp, t);
Packit 5c3484
	  interval_start = t;
Packit 5c3484
	  omitted_p = t;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  mpz_set (ppp, acc);
Packit 5c3484
	}
Packit 5c3484
      interval_end = t;
Packit 5c3484
    }
Packit 5c3484
  printf ("#define SMALLEST_OMITTED_PRIME %d\n", (int) omitted_p);
Packit 5c3484
  printf ("#endif\n");
Packit 5c3484
Packit 5c3484
  printf ("#ifdef WANT_ptab\n");
Packit 5c3484
Packit 5c3484
/*  printf ("static struct gmp_primes_ptab gmp_primes_ptab[] = {\n"); */
Packit 5c3484
Packit 5c3484
  endtok = "";
Packit 5c3484
Packit 5c3484
  mpz_set_ui (ppp, 1);
Packit 5c3484
  interval_start = start_p;
Packit 5c3484
  interval_end = 0;
Packit 5c3484
  np = 0;
Packit 5c3484
  start_idx = 0;
Packit 5c3484
  for (t = start_p; t <= end_p; t += 2)
Packit 5c3484
    {
Packit 5c3484
      if (! isprime (t))
Packit 5c3484
	continue;
Packit 5c3484
Packit 5c3484
      mpz_mul_ui (acc, ppp, t);
Packit 5c3484
Packit 5c3484
      stop = mpz_cmp (acc, Bhalf) >= 0;
Packit 5c3484
      if (!stop)
Packit 5c3484
	{
Packit 5c3484
	  mpn_mod_1s_4p_cps (pre, acc);
Packit 5c3484
	  stop = sumspills (acc, pre + 2, 5);
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (stop)
Packit 5c3484
	{
Packit 5c3484
	  mpn_mod_1s_4p_cps (pre, ppp);
Packit 5c3484
	  printf ("%s", endtok);
Packit 5c3484
	  printf ("  {CNST_LIMB(0x");  mpz_out_str (stdout, 16, ppp);
Packit 5c3484
	  printf ("),{CNST_LIMB(0x");  mpz_out_str (stdout, 16, pre[0]);
Packit 5c3484
	  printf ("),%d", (int) PTR(pre[1])[0]);
Packit 5c3484
	  for (i = 0; i < 5; i++)
Packit 5c3484
	    {
Packit 5c3484
	      printf (",");
Packit 5c3484
	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, pre[2 + i]);
Packit 5c3484
	      printf (")");
Packit 5c3484
	    }
Packit 5c3484
	  printf ("},");
Packit 5c3484
	  printf ("%d,", start_idx);
Packit 5c3484
	  printf ("%d}", np - start_idx);
Packit 5c3484
Packit 5c3484
	  endtok = ",\n";
Packit 5c3484
	  mpz_set_ui (ppp, t);
Packit 5c3484
	  interval_start = t;
Packit 5c3484
	  start_idx = np;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  mpz_set (ppp, acc);
Packit 5c3484
	}
Packit 5c3484
      interval_end = t;
Packit 5c3484
      np++;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  printf ("\n");
Packit 5c3484
  printf ("#endif\n");
Packit 5c3484
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
unsigned long
Packit 5c3484
mpz_log2 (mpz_t x)
Packit 5c3484
{
Packit 5c3484
  return mpz_sgn (x) ? mpz_sizeinbase (x, 2) : 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
mpn_mod_1s_4p_cps (mpz_t cps[7], mpz_t bparm)
Packit 5c3484
{
Packit 5c3484
  mpz_t b, bi;
Packit 5c3484
  mpz_t B1modb, B2modb, B3modb, B4modb, B5modb;
Packit 5c3484
  mpz_t t;
Packit 5c3484
  int cnt;
Packit 5c3484
Packit 5c3484
  mpz_init_set (b, bparm);
Packit 5c3484
Packit 5c3484
  cnt = limb_bits - mpz_log2 (b);
Packit 5c3484
Packit 5c3484
  mpz_init (bi);
Packit 5c3484
  mpz_init (t);
Packit 5c3484
  mpz_init (B1modb);
Packit 5c3484
  mpz_init (B2modb);
Packit 5c3484
  mpz_init (B3modb);
Packit 5c3484
  mpz_init (B4modb);
Packit 5c3484
  mpz_init (B5modb);
Packit 5c3484
Packit 5c3484
  mpz_set_ui (t, 1);
Packit 5c3484
  mpz_mul_2exp (t, t, limb_bits - cnt);
Packit 5c3484
  mpz_sub (t, t, b);
Packit 5c3484
  mpz_mul_2exp (t, t, limb_bits);
Packit 5c3484
  mpz_tdiv_q (bi, t, b);		/* bi = B^2/b, except msb */
Packit 5c3484
Packit 5c3484
  mpz_set_ui (t, 1);
Packit 5c3484
  mpz_mul_2exp (t, t, limb_bits);	/* t = B */
Packit 5c3484
  mpz_tdiv_r (B1modb, t, b);
Packit 5c3484
Packit 5c3484
  mpz_mul_2exp (t, B1modb, limb_bits);
Packit 5c3484
  mpz_tdiv_r (B2modb, t, b);
Packit 5c3484
Packit 5c3484
  mpz_mul_2exp (t, B2modb, limb_bits);
Packit 5c3484
  mpz_tdiv_r (B3modb, t, b);
Packit 5c3484
Packit 5c3484
  mpz_mul_2exp (t, B3modb, limb_bits);
Packit 5c3484
  mpz_tdiv_r (B4modb, t, b);
Packit 5c3484
Packit 5c3484
  mpz_mul_2exp (t, B4modb, limb_bits);
Packit 5c3484
  mpz_tdiv_r (B5modb, t, b);
Packit 5c3484
Packit 5c3484
  mpz_set (cps[0], bi);
Packit 5c3484
  mpz_set_ui (cps[1], cnt);
Packit 5c3484
  mpz_tdiv_q_2exp (cps[2], B1modb, 0);
Packit 5c3484
  mpz_tdiv_q_2exp (cps[3], B2modb, 0);
Packit 5c3484
  mpz_tdiv_q_2exp (cps[4], B3modb, 0);
Packit 5c3484
  mpz_tdiv_q_2exp (cps[5], B4modb, 0);
Packit 5c3484
  mpz_tdiv_q_2exp (cps[6], B5modb, 0);
Packit 5c3484
Packit 5c3484
  mpz_clear (b);
Packit 5c3484
  mpz_clear (bi);
Packit 5c3484
  mpz_clear (t);
Packit 5c3484
  mpz_clear (B1modb);
Packit 5c3484
  mpz_clear (B2modb);
Packit 5c3484
  mpz_clear (B3modb);
Packit 5c3484
  mpz_clear (B4modb);
Packit 5c3484
  mpz_clear (B5modb);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
sumspills (mpz_t ppp, mpz_t *a, int n)
Packit 5c3484
{
Packit 5c3484
  mpz_t s;
Packit 5c3484
  int i, ret;
Packit 5c3484
Packit 5c3484
  mpz_init_set (s, a[0]);
Packit 5c3484
Packit 5c3484
  for (i = 1; i < n; i++)
Packit 5c3484
    {
Packit 5c3484
      mpz_add (s, s, a[i]);
Packit 5c3484
    }
Packit 5c3484
  ret = mpz_cmp (s, B) >= 0;
Packit 5c3484
  mpz_clear (s);
Packit 5c3484
Packit 5c3484
  return ret;
Packit 5c3484
}