285 lines
7.7 KiB
C
285 lines
7.7 KiB
C
|
/* primesieve (BIT_ARRAY, N) -- Fills the BIT_ARRAY with a mask for primes up to N.
|
||
|
|
||
|
Contributed to the GNU project by Marco Bodrato.
|
||
|
|
||
|
THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.
|
||
|
IT IS ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.
|
||
|
IN FACT, IT IS ALMOST GUARANTEED THAT IT WILL CHANGE OR
|
||
|
DISAPPEAR IN A FUTURE GNU MP RELEASE.
|
||
|
|
||
|
Copyright 2010, 2011, 2012 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 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.
|
||
|
|
||
|
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 Lesser General Public
|
||
|
License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General Public License
|
||
|
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
|
||
|
|
||
|
#include "gmp.h"
|
||
|
#include "gmp-impl.h"
|
||
|
|
||
|
/**************************************************************/
|
||
|
/* Section macros: common macros, for mswing/fac/bin (&sieve) */
|
||
|
/**************************************************************/
|
||
|
|
||
|
#define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve) \
|
||
|
__max_i = (end); \
|
||
|
\
|
||
|
do { \
|
||
|
++__i; \
|
||
|
if (((sieve)[__index] & __mask) == 0) \
|
||
|
{ \
|
||
|
(prime) = id_to_n(__i)
|
||
|
|
||
|
#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve) \
|
||
|
do { \
|
||
|
mp_limb_t __mask, __index, __max_i, __i; \
|
||
|
\
|
||
|
__i = (start)-(off); \
|
||
|
__index = __i / GMP_LIMB_BITS; \
|
||
|
__mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS); \
|
||
|
__i += (off); \
|
||
|
\
|
||
|
LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)
|
||
|
|
||
|
#define LOOP_ON_SIEVE_STOP \
|
||
|
} \
|
||
|
__mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1); \
|
||
|
__index += __mask & 1; \
|
||
|
} while (__i <= __max_i) \
|
||
|
|
||
|
#define LOOP_ON_SIEVE_END \
|
||
|
LOOP_ON_SIEVE_STOP; \
|
||
|
} while (0)
|
||
|
|
||
|
/*********************************************************/
|
||
|
/* Section sieve: sieving functions and tools for primes */
|
||
|
/*********************************************************/
|
||
|
|
||
|
#if 0
|
||
|
static mp_limb_t
|
||
|
bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
|
||
|
#endif
|
||
|
|
||
|
/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
|
||
|
static mp_limb_t
|
||
|
id_to_n (mp_limb_t id) { return id*3+1+(id&1); }
|
||
|
|
||
|
/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
|
||
|
static mp_limb_t
|
||
|
n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
|
||
|
|
||
|
#if 0
|
||
|
static mp_size_t
|
||
|
primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
|
||
|
#endif
|
||
|
|
||
|
#if GMP_LIMB_BITS > 61
|
||
|
#define SIEVE_SEED CNST_LIMB(0x3294C9E069128480)
|
||
|
#define SEED_LIMIT 202
|
||
|
#else
|
||
|
#if GMP_LIMB_BITS > 30
|
||
|
#define SIEVE_SEED CNST_LIMB(0x69128480)
|
||
|
#define SEED_LIMIT 114
|
||
|
#else
|
||
|
#if GMP_LIMB_BITS > 15
|
||
|
#define SIEVE_SEED CNST_LIMB(0x8480)
|
||
|
#define SEED_LIMIT 54
|
||
|
#else
|
||
|
#if GMP_LIMB_BITS > 7
|
||
|
#define SIEVE_SEED CNST_LIMB(0x80)
|
||
|
#define SEED_LIMIT 34
|
||
|
#else
|
||
|
#define SIEVE_SEED CNST_LIMB(0x0)
|
||
|
#define SEED_LIMIT 24
|
||
|
#endif /* 7 */
|
||
|
#endif /* 15 */
|
||
|
#endif /* 30 */
|
||
|
#endif /* 61 */
|
||
|
|
||
|
static void
|
||
|
first_block_primesieve (mp_ptr bit_array, mp_limb_t n)
|
||
|
{
|
||
|
mp_size_t bits, limbs;
|
||
|
|
||
|
ASSERT (n > 4);
|
||
|
|
||
|
bits = n_to_bit(n);
|
||
|
limbs = bits / GMP_LIMB_BITS + 1;
|
||
|
|
||
|
/* FIXME: We can skip 5 too, filling with a 5-part pattern. */
|
||
|
MPN_ZERO (bit_array, limbs);
|
||
|
bit_array[0] = SIEVE_SEED;
|
||
|
|
||
|
if ((bits + 1) % GMP_LIMB_BITS != 0)
|
||
|
bit_array[limbs-1] |= MP_LIMB_T_MAX << ((bits + 1) % GMP_LIMB_BITS);
|
||
|
|
||
|
if (n > SEED_LIMIT) {
|
||
|
mp_limb_t mask, index, i;
|
||
|
|
||
|
ASSERT (n > 49);
|
||
|
|
||
|
mask = 1;
|
||
|
index = 0;
|
||
|
i = 1;
|
||
|
do {
|
||
|
if ((bit_array[index] & mask) == 0)
|
||
|
{
|
||
|
mp_size_t step, lindex;
|
||
|
mp_limb_t lmask;
|
||
|
unsigned maskrot;
|
||
|
|
||
|
step = id_to_n(i);
|
||
|
/* lindex = n_to_bit(id_to_n(i)*id_to_n(i)); */
|
||
|
lindex = i*(step+1)-1+(-(i&1)&(i+1));
|
||
|
/* lindex = i*(step+1+(i&1))-1+(i&1); */
|
||
|
if (lindex > bits)
|
||
|
break;
|
||
|
|
||
|
step <<= 1;
|
||
|
maskrot = step % GMP_LIMB_BITS;
|
||
|
|
||
|
lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
|
||
|
do {
|
||
|
bit_array[lindex / GMP_LIMB_BITS] |= lmask;
|
||
|
lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
|
||
|
lindex += step;
|
||
|
} while (lindex <= bits);
|
||
|
|
||
|
/* lindex = n_to_bit(id_to_n(i)*bit_to_n(i)); */
|
||
|
lindex = i*(i*3+6)+(i&1);
|
||
|
|
||
|
lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
|
||
|
for ( ; lindex <= bits; lindex += step) {
|
||
|
bit_array[lindex / GMP_LIMB_BITS] |= lmask;
|
||
|
lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
|
||
|
};
|
||
|
}
|
||
|
mask = mask << 1 | mask >> (GMP_LIMB_BITS-1);
|
||
|
index += mask & 1;
|
||
|
i++;
|
||
|
} while (1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
block_resieve (mp_ptr bit_array, mp_size_t limbs, mp_limb_t offset,
|
||
|
mp_srcptr sieve, mp_limb_t sieve_bits)
|
||
|
{
|
||
|
mp_size_t bits, step;
|
||
|
|
||
|
ASSERT (limbs > 0);
|
||
|
|
||
|
bits = limbs * GMP_LIMB_BITS - 1;
|
||
|
|
||
|
/* FIXME: We can skip 5 too, filling with a 5-part pattern. */
|
||
|
MPN_ZERO (bit_array, limbs);
|
||
|
|
||
|
LOOP_ON_SIEVE_BEGIN(step,0,sieve_bits,0,sieve);
|
||
|
{
|
||
|
mp_size_t lindex;
|
||
|
mp_limb_t lmask;
|
||
|
unsigned maskrot;
|
||
|
|
||
|
/* lindex = n_to_bit(id_to_n(i)*id_to_n(i)); */
|
||
|
lindex = __i*(step+1)-1+(-(__i&1)&(__i+1));
|
||
|
/* lindex = __i*(step+1+(__i&1))-1+(__i&1); */
|
||
|
if (lindex > bits + offset)
|
||
|
break;
|
||
|
|
||
|
step <<= 1;
|
||
|
maskrot = step % GMP_LIMB_BITS;
|
||
|
|
||
|
if (lindex < offset)
|
||
|
lindex += step * ((offset - lindex - 1) / step + 1);
|
||
|
|
||
|
lindex -= offset;
|
||
|
|
||
|
lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
|
||
|
for ( ; lindex <= bits; lindex += step) {
|
||
|
bit_array[lindex / GMP_LIMB_BITS] |= lmask;
|
||
|
lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
|
||
|
};
|
||
|
|
||
|
/* lindex = n_to_bit(id_to_n(i)*bit_to_n(i)); */
|
||
|
lindex = __i*(__i*3+6)+(__i&1);
|
||
|
if (lindex > bits + offset)
|
||
|
continue;
|
||
|
|
||
|
if (lindex < offset)
|
||
|
lindex += step * ((offset - lindex - 1) / step + 1);
|
||
|
|
||
|
lindex -= offset;
|
||
|
|
||
|
lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
|
||
|
for ( ; lindex <= bits; lindex += step) {
|
||
|
bit_array[lindex / GMP_LIMB_BITS] |= lmask;
|
||
|
lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
|
||
|
};
|
||
|
}
|
||
|
LOOP_ON_SIEVE_END;
|
||
|
}
|
||
|
|
||
|
#define BLOCK_SIZE 2048
|
||
|
|
||
|
/* Fills bit_array with the characteristic function of composite
|
||
|
numbers up to the parameter n. I.e. a bit set to "1" represent a
|
||
|
composite, a "0" represent a prime.
|
||
|
|
||
|
The primesieve_size(n) limbs pointed to by bit_array are
|
||
|
overwritten. The returned value counts prime integers in the
|
||
|
interval [4, n]. Note that n > 4.
|
||
|
|
||
|
Even numbers and multiples of 3 are excluded "a priori", only
|
||
|
numbers equivalent to +/- 1 mod 6 have their bit in the array.
|
||
|
|
||
|
Once sieved, if the bit b is ZERO it represent a prime, the
|
||
|
represented prime is bit_to_n(b), if the LSbit is bit 0, or
|
||
|
id_to_n(b), if you call "1" the first bit.
|
||
|
*/
|
||
|
|
||
|
mp_limb_t
|
||
|
gmp_primesieve (mp_ptr bit_array, mp_limb_t n)
|
||
|
{
|
||
|
mp_size_t size;
|
||
|
mp_limb_t bits;
|
||
|
|
||
|
ASSERT (n > 4);
|
||
|
|
||
|
bits = n_to_bit(n);
|
||
|
size = bits / GMP_LIMB_BITS + 1;
|
||
|
|
||
|
if (size > BLOCK_SIZE * 2) {
|
||
|
mp_size_t off;
|
||
|
off = BLOCK_SIZE + (size % BLOCK_SIZE);
|
||
|
first_block_primesieve (bit_array, id_to_n (off * GMP_LIMB_BITS));
|
||
|
for ( ; off < size; off += BLOCK_SIZE)
|
||
|
block_resieve (bit_array + off, BLOCK_SIZE, off * GMP_LIMB_BITS, bit_array, off * GMP_LIMB_BITS - 1);
|
||
|
} else {
|
||
|
first_block_primesieve (bit_array, n);
|
||
|
}
|
||
|
|
||
|
if ((bits + 1) % GMP_LIMB_BITS != 0)
|
||
|
bit_array[size-1] |= MP_LIMB_T_MAX << ((bits + 1) % GMP_LIMB_BITS);
|
||
|
|
||
|
|
||
|
return size * GMP_LIMB_BITS - mpn_popcount (bit_array, size);
|
||
|
}
|
||
|
|
||
|
#undef BLOCK_SIZE
|
||
|
#undef SEED_LIMIT
|
||
|
#undef SIEVE_SEED
|
||
|
#undef LOOP_ON_SIEVE_END
|
||
|
#undef LOOP_ON_SIEVE_STOP
|
||
|
#undef LOOP_ON_SIEVE_BEGIN
|
||
|
#undef LOOP_ON_SIEVE_CONTINUE
|