如何更快地制作这个非常小的C程序?

时间:2016-09-16 12:23:09

标签: c performance loops primes

有没有简单的方法可以让这个小程序更快?我已经完成了作业,这是正确的,但速度太慢。该程序的目的是打印第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方面有一些经验。

4 个答案:

答案 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/2i*i <= number来限制测试循环。

sqrt()的使用存在许多问题:doubleint的范围,准确性,转换为/来自整数。建议避免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;
}