警告:此代码是Project Euler Problem 50的解决方案。如果你不想破坏它,不要看这里。
这里我有一些代码,用于搜索连续素数的长序列,这些素数总和也是素数。有一次,我需要测试一笔金额是否为素数。
我有两个测试,在函数computeMaxPrime中ifdef。第一个检查总和与std ::质数集合。第二个使用GMP实施的Miller-Rabin测试。该函数仅被调用6次。当我使用第一个测试时,函数computeMaxPrime需要.12秒。当我使用第二次测试时,它只需要〜.00002秒。有人能解释一下这有可能吗?我不认为6次调用来检查一个数字是否在一个集合中需要100毫秒。我也尝试使用unordered_set,它也执行相同的操作。
我认为这可能是一个时间问题,但我通过从终端(在OSX上)执行整个程序执行的时间来验证它。我还验证了如果我改变测试以首先使用Miller-Rabin测试,然后确认使用该设置,它会对该设备进行一次调用,并且时钟报告.02秒,这正是我所期望的(1 / 6只使用设定测试的总时间。)
#include "PrimeGenerator2.h"
#include <set>
#include <stdio.h>
#include <time.h>
#include <gmp.h>
typedef std::set<u_int64t> intSet;
bool isInIntSet (intSet set,
u_int64t key)
{
return (set.count(key) > 0);
}
bool isPrime (u_int64t key)
{
mpz_t integ;
mpz_init (integ);
mpz_set_ui (integ, key);
return (mpz_probab_prime_p (integ, 25) > 0);
}
void computeInitialData (const u_int64t limit,
intSet *primeSet,
intList *sumList,
u_int64t *maxCountUpperBound)
{
PrimeSieve sieve;
u_int64t cumSum = 0;
u_int64t pastUpperBound = 0;
*maxCountUpperBound = 0;
for (u_int64t prime = sieve.NextPrime(); prime < limit; prime = sieve.NextPrime()) {
primeSet->insert(prime);
cumSum += prime;
sumList->push_back(cumSum);
if (cumSum < limit)
(*maxCountUpperBound)++;
else
pastUpperBound++;
}
}
u_int64t computeMaxPrime (const u_int64t limit,
const intSet &primeSet,
const intList &sumList,
const u_int64t maxCountUpperBound)
{
for (int maxCount = maxCountUpperBound; ; maxCount--) {
for (int i = 0; i + maxCount < sumList.size(); i++) {
u_int64t sum;
sum = sumList[maxCount + i] - sumList[i];
if (sum > limit)
break;
#if 0
if (isInIntSet (primeSet, sum))
return sum;
#else
if (isPrime (sum))
return sum;
#endif
}
}
return 0; // This should never happen
}
u_int64t findMaxCount (const u_int64t limit)
{
intSet primeSet; // Contains the set of all primes < limit
intList sumList; // Array of cumulative sums of primes
u_int64t maxCountUpperBound = 0; // Used an initial guess for the maximum count
u_int64t maxPrime; // Final return value
clock_t time0, time1, time2;
time0 = clock();
computeInitialData (limit, &primeSet, &sumList, &maxCountUpperBound);
time1 = clock();
maxPrime = computeMaxPrime (limit, primeSet, sumList, maxCountUpperBound);
time2 = clock();
printf ("%f seconds for primes \n" , (double)(time1 - time0)/CLOCKS_PER_SEC);
printf ("%f seconds for search \n" , (double)(time2 - time1)/CLOCKS_PER_SEC);
return maxPrime;
}
int main(void)
{
printf ("%lld\n", findMaxCount(1000000));
}
编辑:哦,甚至更怪异。似乎与STL集无关。如果我做一个hack来使isInIntSet只检查它被调用了多少次,它与GMP测试相比同样慢。这让我觉得我可能只是遇到编译器错误(EDIT2:永远不要责怪编译器!)
bool isInIntSet (intSet set, u_int64t key)
{
static int counter = 0;
counter++;
return (counter == 6);
}
答案 0 :(得分:3)
咄。函数isInIntSet直接将intSet作为参数,因此正在复制整个集合。我打算通过引用传递(intSet&amp; set)。使用unordered_set将搜索时间缩短到.000003秒。