isPrime函数的改进

Improvements for isPrime function

本文关键字:函数 isPrime      更新时间:2023-10-16

互联网上有很多问题需要你找到素数,所以我决定写一组函数来找到它们。我使用Eratosthenes的来生成素数,因为与其他算法相比,它快速且易于实现。然而,我想知道我的代码而不是方法是否效率低下。我用的是STL容器/迭代器吗?我的代码中有没有放慢程序速度的部分?

换句话说,它确实正确地计算了结果,但我想知道的是,它的效率是否可以通过一些算法的改进来提高,而不仅仅是一些代码调整。

任何帮助都将不胜感激。

这是我的代码(如果很难阅读,我深表歉意)

#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
#define initial_prime_barrier 100
bool isFlagged(int i) { return i == 0; }
bool isNextStart(int i) { return i != 0; }
vector<int> generatePrimesBelow(int limit)
{
   vector<int> primes;
   for (int i = 2; i < limit; i++)
   {
      primes.push_back(i);
   }  
   vector<int>::iterator currentStart = primes.begin();
   do
   {
      int numberAtStart = *currentStart;
      vector<int>::iterator currentNumber = currentStart + numberAtStart;
      do
      {
         *currentNumber = 0;
         advance(currentNumber, numberAtStart);
      } while (currentNumber < primes.end());
      currentStart = find_if(currentStart + 1, primes.end(), isNextStart);
   } while ((*currentStart) * (*currentStart) < limit);
   vector<int>::iterator newEnd = remove_if(primes.begin(), primes.end(), isFlagged);
   primes.erase(newEnd, primes.end());
   return primes;
}
bool isPrime(int number)
{
   static vector<int> primes = generatePrimesBelow(initial_prime_barrier);
   static int numPrimes = primes.size();
   static int largestPrime = primes[numPrimes-1];
   static int halfwayPrime = primes[numPrimes/2];
   if (number == largestPrime)
   {
      return true;
   }
   else if (number < largestPrime)
   {
      if (number == halfwayPrime)
      {
         return true;
      }
      else if (number > halfwayPrime)
      {
         for (int i = numPrimes/2; i < numPrimes; i++)
         {
            if (number == primes[i])
            {
               return true;
            }
         }
      }
      else if (number < halfwayPrime)
      {
         for (int i = numPrimes/2; i >= 0; i--)
         {
            if (number == primes[i])
            {
               return true;
            }
         }
      }
   }
   else if (number > largestPrime)
   {
      primes = generatePrimesBelow(number + number);
      numPrimes = primes.size();
      largestPrime = primes[numPrimes-1];
      halfwayPrime = primes[numPrimes/2];
      return isPrime(number);
   }
   return false;
}
int main (int argc, char * const argv[]) 
{
   const int number = 123123;
   cout << (isPrime(number) ? "YES" : "NO") << endl;
}

是的,这是您的方法。有几件事。你不需要你的数组来保存数字,数组中每个条目的地址都是数字本身。您只需要它们保存两个值——truefalse。所以,让你的阵列vector<bool>,它会更加紧凑。然后,在你的内部循环中,你从x+x开始,并按照x的步骤前进。您应该从x*x开始,按照2*x的步骤前进,这将适用于除2之外的所有x。将其设为特殊情况,或者在初始化循环中标记这些偶数。或者将CCD_ 10处的条目视为表示数字CCD_。这应该会加快你的筛选代码。最后,您不需要特殊的find_if调用及其所有机制,只需检查循环中出现的当前条目即可。

(编辑:)在isPrime中,您手动执行二进制搜索,但STL中已经有一个二进制搜索算法。如果您保持vector<bool>筛阵列不变,而不压缩,您就根本不需要它。那么CCD_ 15只需要检查索引CCD_ 16处的数组值是否仍然是CCD_。

(编辑2:)现在,关于效率。您重新计算到n+n,可能是因为预计会有更多的数字需要测试。如果你只测试少数人,简单的赔率划分会更快。如果要测试的数字都在一个狭窄的上部区域,您的最佳选择是偏移筛,下部筛直到测试区域上限的sqrt。如果数字分布广泛,那么可以使用当前的全阵列方法。

这里要使用的关键事实是,在值上m以下大约有n ~= m/log m素数,从0m筛选数组需要O(m*log (log m))时间,而通过r=sqrt b以下的所有素数筛选ab之间的上部区域,即宽度为d=b-a,需要与d*log (log r)成比例的时间。

此外,当增加你的筛子阵列时,最好是扩大,而不是重新计算整个。素数都在那里。为了筛选附属部分,有必要循环通过筛阵列中的所有素数,直到其新上边缘的sqrt。这让人想起分段筛,尽管每个新的分段都代替了前一个分段,或者在任何情况下都与前一个分开。