4

我正在实现一个相当快的素数生成器,并通过对 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;
}

m_sieve是根据埃拉托色尼筛法的布尔数组。我认为这是一种仅考虑素数 2 和 3 的轮分解,按照模式 2、4、2、4、.. 递增。

我想做的是实现一个更大的轮子,也许考虑素数 2,3 和 5。

我已经阅读了很多关于它的文档,但我没有看到任何使用 Eratosthenes 筛子的实现......示例代码可以提供很多帮助,但也有一些提示会很好:) 谢谢。

4

4 回答 4

4

你可以走得更远。这是我几年前写的一些 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 允许循环链表的好技巧。

于 2013-07-26T23:01:33.097 回答
3

为 IBM 工作的澳大利亚数学家 Paul Pritchard 在 1980 年代开发了一系列轮筛。我在我的博客中讨论了其中一个,包括手工编写的示例和 Scheme 中的实现。太大了,这里不讨论。您应该知道,尽管渐近复杂度低于埃拉托色尼筛法,但实施细节通常会使其在实践中变慢。

于 2013-07-26T23:21:19.080 回答
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
于 2013-07-26T23:22:39.097 回答
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)

然后你应该找到这些数字之间的所有差距,并将这些差距组成一个数组以使用它们。

于 2013-08-02T19:19:46.013 回答