我选择在C中执行这些Project Euler问题,因为我的印象是C很快,但似乎并非如此。以下两个循环都极慢:
int problem_7 () {
int n = 0;
for (int i = 1; i <= 10001; i++) {
for (int j = (i==1)?1:n+1; j > 0; j++) {
int factorCounter = 0;
for (int k = 1; k <= j/2; k++)
factorCounter += (j % k == 0);
if (factorCounter == 1) {
n = j;
break;
}
}
}
return n;
}
long long int problem_10 () {
long long int sum = 0;
for (int i = 2; i < 2000000; i++) {
int factorCount = 0;
for (int j = 1; j <= i/2; j++) {
factorCount += (i % j == 0);
sum += i*(j == i/2 && factorCount == 1);
}
}
return sum;
}
有什么方法可以让这些循环运行得更快?他们做了他们应该做的事,但他们每人花了5分钟来执行。
答案 0 :(得分:2)
我想我会回答这个问题。你的程序很慢,因为你的循环设计很差而且嵌套很差。我不打算进行复杂性分析,但是你在O(N ^ x)的范围内,其中x> 4(据我所知)。
这只是糟糕的编程,它与循环优化几乎没有关系。你需要使用像Sieve of Eratosthenes这样的东西来解决Euler 7.我不会在这里给你解决方案,就像维基文章那样解决它是相当简单的。
答案 1 :(得分:2)
使用布尔数值的分支预测不是必需的:
以问题7为例,这可以通过使用 if语句来加速:
int n = 0;
for (int i = 1; i <= 10001; i++) {
for (int j = (i==1)?1:n+1; j > 0; j++) {
int factorCounter = 0;
for (int k = 1; k <= j/2; k++)
{
if (j%k==0) // code is changed HERE
{
factorCounter ++;
if (factorCounter > 1)
{
break;
}
} // code change ends here
}
if (factorCounter == 1) {
n = j;
break;
}
}
这完成了 0.88secs 而不是原来的 9.5secs - 比这一次更改快了10倍
优化解释和对等理性:
所做的更改来自原始行:
factorCounter += (j % k == 0);
首先将其改为等效的:
if (j%k==0)
{
factorCounter ++;
}
注意factorCounter
只能递增,并且在循环之后,任何超过1的值都会被丢弃,因为(factorCounter == 1)
将为false,所以一旦它大于1,就没有理由继续循环。另请注意factorCounter
的值只能在(j%k==0)
时更改,因此{if}}的测试应该在if检查中发生,代码现在是:
factorCounter > 1
早期退出循环就是性能增益
答案 2 :(得分:1)
C很快。更高级别的语言也可以更快。但即使是最好的编译器也无法优化你所做的额外操作!如果factorCounter变得大于1,减少问题7算法中操作次数的一种简单方法就是打破最深的循环。抱歉打破它但是:它不是编译器它是算法!
答案 3 :(得分:1)
几乎可以立即执行更直接的问题。你真的不需要那么多的优化。
#include <iostream>
#include <cmath>
using namespace std;
bool isPrime(int j)
{
for(int fac = 2; fac < sqrt(j)+0.5; ++fac)
if(j%fac == 0)
return false;
return true;
}
int main()
{
int primesFound = 1; // 2 is prime
int possiblePrime = 1;
while(primesFound != 10001)
{
possiblePrime += 2;
if(isPrime(possiblePrime))
++primesFound;
}
cout << possiblePrime << endl;
}