2013-07-26 2 views
2

Я реализую достаточно быстрый генератор простых чисел, и я получил неплохие результаты с несколькими оптимизациями на сите эратосфенов. В частности, в ходе предварительной части алгоритма, я пропустить все кратные 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 ... пример кода мог бы помочь много, но и некоторые подсказки были бы приятными :) Спасибо.

+0

Что вы хотите сказать? Вы ищете сито эрафосфенового кода? –

+0

http://stackoverflow.com/questions/8341295/2-3-5-7-wheel-factorization-seems-to-skip-prime-number-331 имеет реализацию Haskell в ответах. –

+0

Прошу прощения, если я не был ясен: я бы хотел пропустить все кратные 2,3 и 5, как я уже делаю для кратных 2 и 3. И нет, мне не нужно сито из эратосфена код – Crybot

ответ

2

Вы можете пойти еще дальше. Вот некоторые 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 позволяет циклического связного списка.

+0

спасибо. Я не знаю этого языка, но я постараюсь понять :) – Crybot

+0

Важная часть - это жестко обозначенный список различий. 2,4,2,4,6 => 11 + 2 = 3, 13 + 4 = 16, 17 + 2 = 19, 19 + 4 = 23, 23 + 6 = 29 ... Я удаляю кратное 2 3 5 7 – hivert

+0

Есть ли способ рассчитать эти значения? – Crybot

2

Пол Притчард, австралийский математик, работающий в IBM, разработал серию колесных сит в 1980-х годах. Я обсуждаю один из них в my blog, включая примеры, выполненные вручную, и реализацию на Схеме. Здесь слишком много, чтобы обсудить здесь. Вы должны знать, что, хотя асимптотическая сложность меньше, чем сито Эратосфена, детали реализации обычно делают его более медленным на практике.

+0

Спасибо за ссылку, я ее прочитаю;) – Crybot

+1

Используя 2, 3 и 5, я получил ускорение фактора 3 на Java. – starblue

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 
+0

Спасибо :) это помогло – Crybot

+0

2-4 колесо проще программировать: 2 * 3 = 6. 'step = 6 - step' дает шаги 2, 4, 2, 4, ... Не забудьте начать с 5 и испытание отдельно для делителей 2 и 3. – rossum

0

Там гораздо лучше оптимизации его (она занимает O (п) операций вместо O (N журнал журнал п) для вашего варианта): https://stackoverflow.com/a/17550147/2559094, но он занимает больше памяти (использует n + n/log n memory вместо n).

Если вы все еще хотите продолжить свою оптимизацию и считаете простые числа p1, p2, ..., pn, вы должны записать все числа от 0 до p1 * p2 * ... * pn (используйте lcm на случай, если вы решили использовать не только простые числа) и проверить, какие из них удовлетворяют следующей системе: x! = 0 (mod p1) x! = 0 (mod p2) ... x! = 0 (mod pn)

Затем вы должны найти все промежутки между этими числами и создать массив этих пробелов для их использования.

Смежные вопросы