我正在实施一个相当快速的素数发生器,我通过对eratosthenes筛子的一些优化获得了一些不错的结果。特别是,在算法的初步部分,我以这种方式跳过所有2和3的倍数:
template<class Sieve, class SizeT>
void PrimeGenerator<Sieve, SizeT>::factorize()
{
SizeT c = 2;
m_sieve[2] = 1;
m_sieve[3] = 1;
for (SizeT i=5; i<m_size; i += c, c = 6 - c)
m_sieve[i] = 1;
}
根据eratosthenes的筛子,m_sieve是一个布尔数组。 我认为这是一种只考虑素数2和3的车轮分解,按照模式2,4,2,4进行递增。我想要做的是实现更大的轮子,可能考虑质数2,3和5。 我已经阅读了很多关于它的文档,但是我没有看到任何关于eratosthenes筛选的实现...示例代码可以帮助很多,但也有一些提示会很好:) 感谢。
答案 0 :(得分:3)
你可以走得更远。这是我几年前写的一些OCaml代码:
let eratosthene borne =
let remove_multiples a lst =
let rec remmult multa li accu = function
[] -> rev accu
| head::tail ->
if multa = head
then remmult (a*(hd li)) (tl li) accu tail
else remmult multa li (head::accu) tail
in
remmult (a * a) lst [] lst
in
let rec first_primes accu ll =
let a = hd ll in
if a * a > borne then (rev accu) @ ll
else first_primes (a::accu) (remove_multiples a (tl ll))
in
let start_list =
(* Hard code of the differences of consecutive numbers that are prime*)
(* with 2 3 5 7 starting with 11... *)
let rec lrec = 2 :: 4 :: 2 :: 4 :: 6 :: 2 :: 6 :: 4 :: 2 :: 4 :: 6
:: 6 :: 2 :: 6 :: 4 :: 2 :: 6 :: 4 :: 6 :: 8 :: 4 :: 2 :: 4 :: 2
:: 4 :: 8 :: 6 :: 4 :: 6 :: 2 :: 4 :: 6 :: 2 :: 6 :: 6 :: 4 :: 2
:: 4 :: 6 :: 2 :: 6 :: 4 :: 2 :: 4 :: 2 :: 10 :: 2 :: 10 :: lrec
and listPrime2357 a llrec accu =
if a > borne then rev accu
else listPrime2357 (a + (num (hd llrec))) (tl llrec) (a::accu)
in
listPrime2357 (num 11) lrec []
in
first_primes [(num 7);(num 5);(num 3);(num 2)] start_list;;
注意OCaml允许循环链表的好技巧。
答案 1 :(得分:2)
为IBM工作的澳大利亚数学家Paul Pritchard在20世纪80年代开发了一系列轮式筛子。我在my blog讨论其中一个,包括手工制作的示例和Scheme中的实现。这里讨论太大了。您应该意识到,虽然渐近复杂度小于Eratosthenes的Sieve,但实现细节通常会使其在实践中变慢。
答案 2 :(得分:2)
2 * 3 * 5 = 30
辐条= 2,3,4,5,6,8,9,10,12,15,16,18,20,24,30
辐条之间的数字:1,7,11,13,17,19,23,25,29
int[] gaps = [6,4,2,4,2,4,2,4];
int[] primes = [2,3,5];
int max = 9001;
int counter, max_visited;
while(max_visited < max) {
int jump = gaps[counter];
counter = counter + 1 % gaps.length;
max_visited += jump;
}
这有帮助吗?
或者,这可能是你想要的,伪代码:
primes = [2,3,5];
product = multiply(primes);//imaginary function that returns 30
wheel = new int[product];
foreach(prime in primes)
for(int x = 1; x <= product/prime; x++)
wheel[prime*x] = 1;
return wheel
答案 3 :(得分:0)
它有一个更好的优化(它需要O(n)操作而不是O(n log log n)为你的变体):https://stackoverflow.com/a/17550147/2559094,但它需要更多的内存(使用n + n / log n记忆而不是n)。
如果您仍想继续进行优化并考虑质数p1,p2,...,pn,则应将所有数字从0写入p1 * p2 * ... * pn(如果您决定使用lcm不仅使用素数)并检查其中哪些满足以下系统: x!= 0(mod p1) x!= 0(mod p2) ... x!= 0(mod pn)
然后你应该找到这些数字之间的所有间隙,并制作一个这些间隙的数组来使用它们。