Сита оптимизации кода Atkin

Мне было интересно, есть ли у кого-нибудь предложения о том, что я могу сделать, чтобы улучшить скорость выполнения моего кода. Я написал Sieve of Atkin функция, которая возвращает вектор, включая все простые числа из [2, max] включительно.

Вот мой код

void atkin_sieve (unsigned int max, std::vector <unsigned int> & primes) {
// Sieve array up to max defaulted to false
// Index's [0, max] correspond to numbers
// Dynamic memory so all values default false
bool* sieve = new bool [max + 1];
// Square root of max number
unsigned int sqrt_max = int (sqrt (max));
// Unsigned integers declared to save time
unsigned int n, x, y;

// TODO - Explain this
for (x = 1; x < sqrt_max; x++) {
for (y = 1; y < sqrt_max; y++) {
n = (4 * x * x) + (y * y);
if (n <= max && (n % 12 == 1 || n % 12 == 5))
sieve [n] = !sieve [n];
n = (3 * x * x) + (y * y);
if (n <= max && (n % 12 == 7))
sieve [n] = !sieve [n];
n = (3 * x * x) - (y * y);
if (x > y && n <= max && (n % 12 == 11))
sieve [n] = !sieve [n];
}
}

// TODO - Explain this
for (x = 5; x < sqrt_max; x++) {
if (sieve [x]) {
n = x * x;
for (y = n; y <= max; y += n)
sieve [y] = false;
}
}

// Push primes 2, 3, and 5
primes.push_back(2);
primes.push_back(3);
primes.push_back(5);
// Start from prime 7, skip even numbers
for (x = 7; x <= max; x += 2) {
// If the number is prime
if (sieve [x])
// Push it into the vector
primes.push_back(x);
}

// Delete the sieve array
delete [] sieve;
}

У меня есть несколько вопросов о том, что я мог бы сделать лучше, чтобы оптимизировать эту функцию.

Я инициализировал массив sieve как динамический массив логических выражений, чтобы все они по умолчанию имели значение false, быстрее ли будет иметь такое же динамическое сито или я должен сохранить его как обычный массив?

Я сохраняю простые числа в векторе, используя цикл for после обработки алгоритма. Есть ли более быстрый способ найти все простые числа в сите для сохранения их в векторе?

Любые другие советы, хитрости, подсказки или код приветствуются и очень ценятся, спасибо.

0

Решение

В зависимости от того, сколько простых чисел вы возвращаете, используя std::vector может вызывать проблему, каждый раз, когда вектор должен расти для обработки большего количества объектов, чем его емкость, ему, вероятно, потребуется создать новый массив и скопировать все значения из старого массива в новый. Рассмотрите возможность использования std::list или std::deque чтобы избежать этой проблемы. Если вам действительно нужно vector может быть быстрее выполнить цикл и подсчитать количество простых чисел, затем reserve такой большой размер в векторе, так что вектор никогда не должен расти.

Вы, вероятно, должны выполнить некоторое профилирование кода — как вы это сделаете, зависит от вашей среды разработки. Это должно сказать вам, где тратится большая часть вашего кода. Без этой информации вы могли бы потратить целую вечность на оптимизацию одной части кода, если это не окажет большого влияния на результат.

По крайней мере, добавьте некоторый временной код, чтобы вы могли видеть, помогают ли вам какие-либо изменения, и насколько.

Лучшая оптимизация — это, как правило, изменение алгоритма, обычно такие вещи, как развертывание цикла и т. Д., Лучше оставить на усмотрение компилятора, если только код не особенно критичен по времени (даже тогда, может быть, и нет).

Кроме того, убедитесь, что вы компилируете с оптимизацией — это может иметь огромное значение.

0

Другие решения

Как подсказал другой ответ, профилирование — лучший способ понять, куда идет время.

Некоторые предложения и комментарии, некоторые из которых, вероятно, очевидны

  • Я не верю, что у вас есть гарантия нулевой инициализации при распределении сита; для этого вам нужно использовать bool *sieve = new bool[max+1]();, Если вы обнаружите, что все работает правильно, то вам здесь или повезло, или вы работаете под компилятором, который инициализирует отладочные сборки с нуля. Если это так, попробуйте сборку релиза с включенной оптимизацией, и вы увидите некоторое ускорение.

  • Ваш bool[] Скорее всего, не будет использовать 1 бит на элемент, но, вероятно, байта. Вы можете найти с помощью std::vector<bool> более эффективный, поскольку обычно специализируется на плотном хранении логических значений — 1 бит на бул. Вы будете торговать с уменьшенным объемом памяти по сравнению с повышенной сложностью чтения / записи отдельного логического значения.

  • Попробуйте предварительно изменить размер массива простых чисел max / log(max)с соответствующей проверкой входных данных, в качестве приближения к числу простых чисел, меньших, чем макс.

  • Если функция вызывается повторно в вашем приложении, попробуйте повторно использовать предыдущие ситовые массивы для ответа на последующие вызовы.

0

По вопросам рекламы [email protected]