有没有简单的方法可以让这个小程序更快?我已经完成了作业,这是正确的,但速度太慢。该程序的目的是打印第n对素数,其中两者之间的差异为2,给定n。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
bool isPrime(int number) {
for (int i = 3; i <= number/2; i += 2) {
if (!(number%i)) {
return 0;
}
}
return 1;
}
int findNumber(int n) {
int prevPrime, currentNumber = 3;
for (int i = 0; i < n; i++) {
do {
prevPrime = currentNumber;
do {
currentNumber+=2;
} while (!isPrime(currentNumber));
} while (!(currentNumber - 2 == prevPrime));
}
return currentNumber;
}
int main(int argc, char *argv[]) {
int numberin, numberout;
scanf ("%d", &numberin);
numberout = findNumber(numberin);
printf("%d %d\n", numberout - 2, numberout);
return 0;
}
我考虑使用某种类型的数组或列表,其中包含在当前数字之前找到的所有素数,并将每个数字除以此列表而不是所有数字,但我们还没有真正涵盖这些不同的数据结构,所以我觉得我应该能够解决这个问题。我刚从C开始,但我在Python和Java方面有一些经验。
答案 0 :(得分:2)
要找到相差2的素数对,你只需找到一个素数然后加2并测试它是否也是素数。
if (isPrime(x) && isPrime(x+2)) { /* found pair */ }
要查找素数,最佳算法是Sieve of Eratosthenes。您需要构建一个最多为(N)的查找表,其中N是您可以获得的最大数量。如果数字为素数,您可以使用Sieve进入O(1)。在构建Sieve时,您可以构建已排序素数的列表。
如果您的N很大,您也可以从数字P为素数的事实中获益,如果它没有任何素数因子&lt; = SQRT(P)(因为如果它有一个因子&gt; SQRT(N)那么它也应该有一个&lt; SQRT(N))。您可以构建一个大小为SQRT(N)的Eratosthenes筛,以获得素数列表,然后测试是否有任何这些素数除以P.如果没有除P,则P为素数。
通过这种方法,您可以相对快速地测试数字达到10亿左右,而且内存很少。
答案 1 :(得分:1)
以下是isPrime
中加速循环的改进:
bool isPrime(int number) {
for (int i = 3; i * i <= number; i += 2) { // Changed the loop condition
if (!(number%i)) {
return 0;
}
}
return 1;
}
答案 2 :(得分:1)
您比必要时更频繁地致电isPrime
。你写了
currentNummber = 3;
/* ... */
do {
currentNumber+=2;
} while (!isPrime(currentNumber));
...这意味着每个奇数都会调用isPrime
。但是,当您确定例如5是素数,你已经知道10,15,20等不会是素数,所以你不需要测试它们。
当使用筛网过滤器时,这种“挖出”多次质数的方法是完成的,参见例如Sieve of Eratosthenes algorithm in C用于实现C中素数的筛选过滤器。
答案 3 :(得分:0)
避免测试第三位候选人
只能找到a, a+2
对素数a = 6*n + 5
。 (第3,5对除外)。
为什么?
a + 0 = 6*n + 5 Maybe a prime
a + 2 = 6*n + 7 Maybe a prime
a + 4 = 6*n + 9 Not a prime when more than 3 as 6*n + 9 is a multiple of 3
所以不要用+ 2
测试其他整数,而是用
a = 5;
loop {
if (isPrime(a) && isPrime(a+2)) PairCount++;
a += 6;
}
改善循环退出测试
许多处理器/编译器在计算剩余部分时,也可用于几乎&#34; free&#34; CPU时间成本,商。因人而异。使用商而不是i <= number/2
或i*i <= number
来限制测试循环。
sqrt()
的使用存在许多问题:double
与int
的范围,准确性,转换为/来自整数。建议避免sqrt()
执行此任务。
使用unsigned
获取更多范围。
bool isPrime(unsigned x) {
// With OP's selective use, the following line is not needed.
// Yet needed for a general purpose `isPrime()`
if (x%2 == 0) return x == 2;
if (x <= 3) return x == 3;
unsigned p = 1;
unsigned quotient, remainder;
do {
p += 2;
remainder = x%p;
if (remainder == 0) return false;
quotient = x/p; // quotient for "free"
} while (p < quotient); // Low cost compare
return true;
}