Причина, по которой ваш второй пример занимает больше времени, заключается в том, что вы итерируете std::list
.
A std::list
в C ++ - это связанный список, что означает, что он не использует непрерывную память.Это плохо, потому что для итерации списка вы должны переходить от узла к узлу непредсказуемым образом (к процессору / сборщику).Кроме того, вы, скорее всего, «используете» только несколько байтов каждой кеш-линии.Оперативная память медленная.Извлечение байта из ОЗУ занимает лот дольше, чем извлечение его из L1.В наши дни процессоры работают быстро, поэтому ваша программа большую часть времени ничего не делает и ожидает поступления памяти.
Вместо этого используйте std::vector
.Он хранит все значения один за другим, и итерация очень дешевая.Поскольку вы выполняете итерацию вперед в памяти без скачков, вы используете full кешлайн, и ваш модуль предварительной выборки сможет извлекать дополнительные страницы, прежде чем они понадобятся, потому что ваш доступ к памяти предсказуем.
Многие люди, в том числе Бьярно Страуструп, доказали, что std::vector
во многих случаях быстрее, чем std::list
, даже в тех случаях, когда std::list
имеет "теоретически" лучшую сложность (случайная вставка, удаление,...) только потому, что кэширование очень помогает.Поэтому всегда используйте std::vector
по умолчанию.И если вы думаете , связанный список будет быстрее в вашем случае, измерьте , и вы будете удивлены, что - большую часть времени - std::vector
доминирует.
Редактировать: как уже отмечали другие, ваш метод поиска простых чисел не очень эффективен.Я просто немного поиграл и применил Сито Эратосфена с использованием набора битов.
constexpr int max_prime = 1000000000;
std::bitset<max_prime> *bitset = new std::bitset<max_prime>{};
// Note: Bit SET means NO prime
bitset->set(0);
bitset->set(1);
for(int i = 4; i < max_prime ; i += 2)
bitset->set(i); // set all even numbers
int max = sqrt(max_prime);
for(int i = 3; i < max; i += 2) { // No point testing even numbers as they can't be prime
if(!bitset->test(i)) { // If i is prime
for(int j = i * 2; j < no_primes; j += i)
bitset->set(j); // set all multiples of i to non-prime
}
}
Это занимает от 4,2 до 4,5 секунд 30 секунд (не знаю почемупосле небольших модификаций он сильно изменился ... должно быть, это оптимизация, которой я больше не занимаюсь), чтобы найти все простые числа менее одного миллиарда (1 000 000 000) на моей машине.Ваш подход занял слишком много времени даже для 100 миллионов.Примерно через две минуты я отменил поиск в 1 миллиард.
Сравнение для 100 миллионов:
time taken: 63.515 seconds
time taken bitset: 1.874 seconds
No of divisions : 1975961174
No of primes found: 5761455
No of primes found bitset: 5761455
Я не математик, поэтому я уверен, что есть еще способы оптимизировать егодалее я оптимизирую только для четных чисел.