| /* gen-trialdivtab.c |
| |
| Contributed to the GNU project by Torbjorn Granlund. |
| |
| Copyright 2009, 2012, 2013, 2016, 2018 Free Software Foundation, Inc. |
| |
| This file is part of the GNU MP Library. |
| |
| The GNU MP Library is free software; you can redistribute it and/or modify |
| it under the terms of either: |
| |
| * the GNU Lesser General Public License as published by the Free |
| Software Foundation; either version 3 of the License, or (at your |
| option) any later version. |
| |
| or |
| |
| * the GNU General Public License as published by the Free Software |
| Foundation; either version 2 of the License, or (at your option) any |
| later version. |
| |
| or both in parallel, as here. |
| |
| The GNU MP Library is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received copies of the GNU General Public License and the |
| GNU Lesser General Public License along with the GNU MP Library. If not, |
| see https://www.gnu.org/licenses/. */ |
| |
| /* |
| Generate tables for fast, division-free trial division for GMP. |
| |
| There is one main table, ptab. It contains primes, multiplied together, and |
| several types of pre-computed inverses. It refers to tables of the type |
| dtab, via the last two indices. That table contains the individual primes in |
| the range, except that the primes are not actually included in the table (see |
| the P macro; it sneakingly excludes the primes themselves). Instead, the |
| dtab tables contains tuples for each prime (modular-inverse, limit) used for |
| divisibility checks. |
| |
| This interface is not intended for division of very many primes, since then |
| other algorithms apply. |
| */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include "bootstrap.c" |
| |
| int sumspills (mpz_t, mpz_t *, int); |
| void mpn_mod_1s_4p_cps (mpz_t [7], mpz_t); |
| |
| int limb_bits; |
| |
| mpz_t B; |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| int t, p; |
| mpz_t ppp, acc, inv, gmp_numb_max, tmp, Bhalf; |
| mpz_t pre[7]; |
| int i; |
| int start_p, end_p, interval_start, interval_end, omitted_p; |
| const char *endtok; |
| int stop; |
| int np, start_idx; |
| |
| if (argc < 2) |
| { |
| fprintf (stderr, "usage: %s bits endprime\n", argv[0]); |
| exit (1); |
| } |
| |
| limb_bits = atoi (argv[1]); |
| |
| end_p = 1290; /* default end prime */ |
| if (argc == 3) |
| end_p = atoi (argv[2]); |
| |
| printf ("#if GMP_LIMB_BITS != %d\n", limb_bits); |
| printf ("#error This table is for GMP_LIMB_BITS = %d\n", limb_bits); |
| printf ("#endif\n\n"); |
| |
| printf ("#if GMP_NAIL_BITS != 0\n"); |
| printf ("#error This table does not support nails\n"); |
| printf ("#endif\n\n"); |
| |
| for (i = 0; i < 7; i++) |
| mpz_init (pre[i]); |
| |
| mpz_init (B); |
| mpz_setbit (B, limb_bits); |
| mpz_init_set (gmp_numb_max, B); |
| mpz_sub_ui (gmp_numb_max, gmp_numb_max, 1); |
| |
| mpz_init (tmp); |
| mpz_init (inv); |
| |
| mpz_init (Bhalf); |
| mpz_setbit (Bhalf, limb_bits - 1); |
| |
| start_p = 3; |
| |
| mpz_init_set_ui (ppp, 1); |
| mpz_init (acc); |
| interval_start = start_p; |
| omitted_p = 3; |
| interval_end = 0; |
| |
| /* printf ("static struct gmp_primes_dtab gmp_primes_dtab[] = {\n"); */ |
| |
| printf ("#ifdef WANT_dtab\n"); |
| |
| for (t = start_p; t <= end_p; t += 2) |
| { |
| if (! isprime (t)) |
| continue; |
| |
| mpz_mul_ui (acc, ppp, t); |
| stop = mpz_cmp (acc, Bhalf) >= 0; |
| if (!stop) |
| { |
| mpn_mod_1s_4p_cps (pre, acc); |
| stop = sumspills (acc, pre + 2, 5); |
| } |
| |
| if (stop) |
| { |
| for (p = interval_start; p <= interval_end; p += 2) |
| { |
| if (! isprime (p)) |
| continue; |
| |
| printf (" P(%d,", (int) p); |
| mpz_invert_ui_2exp (inv, p, limb_bits); |
| printf ("CNST_LIMB(0x"); mpz_out_str (stdout, 16, inv); printf ("),"); |
| |
| mpz_tdiv_q_ui (tmp, gmp_numb_max, p); |
| printf ("CNST_LIMB(0x"); mpz_out_str (stdout, 16, tmp); |
| printf (")),\n"); |
| } |
| mpz_set_ui (ppp, t); |
| interval_start = t; |
| omitted_p = t; |
| } |
| else |
| { |
| mpz_set (ppp, acc); |
| } |
| interval_end = t; |
| } |
| printf ("#define SMALLEST_OMITTED_PRIME %d\n", (int) omitted_p); |
| printf ("#endif\n"); |
| |
| printf ("#ifdef WANT_ptab\n"); |
| |
| /* printf ("static struct gmp_primes_ptab gmp_primes_ptab[] = {\n"); */ |
| |
| endtok = ""; |
| |
| mpz_set_ui (ppp, 1); |
| interval_start = start_p; |
| interval_end = 0; |
| np = 0; |
| start_idx = 0; |
| for (t = start_p; t <= end_p; t += 2) |
| { |
| if (! isprime (t)) |
| continue; |
| |
| mpz_mul_ui (acc, ppp, t); |
| |
| stop = mpz_cmp (acc, Bhalf) >= 0; |
| if (!stop) |
| { |
| mpn_mod_1s_4p_cps (pre, acc); |
| stop = sumspills (acc, pre + 2, 5); |
| } |
| |
| if (stop) |
| { |
| mpn_mod_1s_4p_cps (pre, ppp); |
| printf ("%s", endtok); |
| printf (" {CNST_LIMB(0x"); mpz_out_str (stdout, 16, ppp); |
| printf ("),{CNST_LIMB(0x"); mpz_out_str (stdout, 16, pre[0]); |
| printf ("),%d", (int) PTR(pre[1])[0]); |
| for (i = 0; i < 5; i++) |
| { |
| printf (","); |
| printf ("CNST_LIMB(0x"); mpz_out_str (stdout, 16, pre[2 + i]); |
| printf (")"); |
| } |
| printf ("},"); |
| printf ("%d,", start_idx); |
| printf ("%d}", np - start_idx); |
| |
| endtok = ",\n"; |
| mpz_set_ui (ppp, t); |
| interval_start = t; |
| start_idx = np; |
| } |
| else |
| { |
| mpz_set (ppp, acc); |
| } |
| interval_end = t; |
| np++; |
| } |
| |
| printf ("\n"); |
| printf ("#endif\n"); |
| |
| return 0; |
| } |
| |
| unsigned long |
| mpz_log2 (mpz_t x) |
| { |
| return mpz_sgn (x) ? mpz_sizeinbase (x, 2) : 0; |
| } |
| |
| void |
| mpn_mod_1s_4p_cps (mpz_t cps[7], mpz_t bparm) |
| { |
| mpz_t b, bi; |
| mpz_t B1modb, B2modb, B3modb, B4modb, B5modb; |
| mpz_t t; |
| int cnt; |
| |
| mpz_init_set (b, bparm); |
| |
| cnt = limb_bits - mpz_log2 (b); |
| |
| mpz_init (bi); |
| mpz_init (t); |
| mpz_init (B1modb); |
| mpz_init (B2modb); |
| mpz_init (B3modb); |
| mpz_init (B4modb); |
| mpz_init (B5modb); |
| |
| mpz_set_ui (t, 1); |
| mpz_mul_2exp (t, t, limb_bits - cnt); |
| mpz_sub (t, t, b); |
| mpz_mul_2exp (t, t, limb_bits); |
| mpz_tdiv_q (bi, t, b); /* bi = B^2/b, except msb */ |
| |
| mpz_set_ui (t, 1); |
| mpz_mul_2exp (t, t, limb_bits); /* t = B */ |
| mpz_tdiv_r (B1modb, t, b); |
| |
| mpz_mul_2exp (t, B1modb, limb_bits); |
| mpz_tdiv_r (B2modb, t, b); |
| |
| mpz_mul_2exp (t, B2modb, limb_bits); |
| mpz_tdiv_r (B3modb, t, b); |
| |
| mpz_mul_2exp (t, B3modb, limb_bits); |
| mpz_tdiv_r (B4modb, t, b); |
| |
| mpz_mul_2exp (t, B4modb, limb_bits); |
| mpz_tdiv_r (B5modb, t, b); |
| |
| mpz_set (cps[0], bi); |
| mpz_set_ui (cps[1], cnt); |
| mpz_tdiv_q_2exp (cps[2], B1modb, 0); |
| mpz_tdiv_q_2exp (cps[3], B2modb, 0); |
| mpz_tdiv_q_2exp (cps[4], B3modb, 0); |
| mpz_tdiv_q_2exp (cps[5], B4modb, 0); |
| mpz_tdiv_q_2exp (cps[6], B5modb, 0); |
| |
| mpz_clear (b); |
| mpz_clear (bi); |
| mpz_clear (t); |
| mpz_clear (B1modb); |
| mpz_clear (B2modb); |
| mpz_clear (B3modb); |
| mpz_clear (B4modb); |
| mpz_clear (B5modb); |
| } |
| |
| int |
| sumspills (mpz_t ppp, mpz_t *a, int n) |
| { |
| mpz_t s; |
| int i, ret; |
| |
| mpz_init_set (s, a[0]); |
| |
| for (i = 1; i < n; i++) |
| { |
| mpz_add (s, s, a[i]); |
| } |
| ret = mpz_cmp (s, B) >= 0; |
| mpz_clear (s); |
| |
| return ret; |
| } |