书中的C ++ Prime数字任务

时间:2010-06-27 23:19:15

标签: c++

我是C ++初学者;) 下面的代码有多好,可以找到2-1000之间的所有素数:

int i, j;

for (i=2; i<1000; i++) {
  for (j=2; j<=(i/j); j++) {
    if (! (i%j))
      break;
    if (j > (i/j))
      cout << i << " is prime\n";
  }
}

6 个答案:

答案 0 :(得分:9)

当j = i时你停止。 第一个简单的优化是在j = sqrt(i)时停止(因为不存在大于其平方根的因子)。

更快的实现是例如sieve of eratosthenes

编辑:代码看起来有点神秘,所以这是它的工作方式:

内部for的终止条件是i/j,相当于j<i(更清楚),因为当最终有j==i时,我们会i/j==0并且for会破裂。

下一次检查if(j>(i/j))真的很讨厌。基本上它只是检查循环是否达到for的结束条件(因此我们有一个素数)或者如果我们达到显式中断(没有素数)。如果我们达到了结尾,那么j==i+1(考虑一下)=&gt; i/j==0 =&gt;这是一个素数。如果我们中断,则意味着ji的因子,但不仅仅是任何因素,实际上是最小的(因为我们在第一个j处退出,除以{{1} }})! 由于i是最小因素,因此另一个因素(或剩余因子的乘积,由j给出)将大于或等于i/j,因此进行测试。如果j,我们会休息一下,j<=i/jj的最小因素。

这是一些难以理解的代码!

答案 1 :(得分:0)

不是很好。在我的拙见中,缩进和间距是可怕的(没有冒犯)。为了清理一些:

int i, j;

for (i=2; i<1000; i++) {
    for (j=2; i/j; j++) {
        if (!(i % j))
            break;
        if (j > i/j)
            cout << i << " is prime\n";
    }
}

这揭示了一个错误:if (j > i/j) ...需要位于内循环的外部才能实现。此外,我认为i/j条件更令人困惑(更不用说速度慢),而不仅仅是说j < i(甚至没有,因为一旦j到达i,{{ 1}}将是0)。在这些变化之后,我们有:

i % j

这很有效。然而,int i, j; for (i=2; i<1000; i++) { for (j=2; j < i; j++) { if (!(i % j)) break; } if (j > i/j) cout << i << " is prime\n"; } 混淆了我。我甚至无法弄清楚它为什么会起作用(我想如果我花了一段时间我可以搞清楚looking like this guy)。我会改为写j > i/j

您在此处实施的内容称为trial division。一个更好的算法是Eratosthenes的筛选,如另一个答案中所述。如果您实施了Eratosthenes筛选,还有几件事要检查:

  1. 它应该有用。
  2. 不应使用除法或模数。并非这些都是“坏”(被授予,它们往往比加法,减法,否定等慢一个数量级),但它们不是必需的,如果它们存在,则可能意味着实现不是真的那么高效。
  3. 它应该能够在大约一秒钟内计算小于10,000,000的质数(取决于您的硬件,编译器等)。

答案 2 :(得分:0)

首先,你的代码既简短又正确,这在初学者时非常好。 ; - )

这就是我要改进代码的方法:

1)定义循环内的变量,这样它们就不会与其他东西混淆。我也会使绑定参数或常量。

#define MAX 1000
for(int i=2;i<MAX;i++){ 
    for(int j=2;j<i/j;j++){ 
        if(!(i%j)) break; 
        if(j>(i/j)) cout<<i<<" is prime\n"; 
    }
}

2)我会使用Sieve of Eratosthenes,正如Joey Adams和Mau所建议的那样。注意我怎么不必写两次绑定,所以这两个用法总是相同的。

#define MAX 1000
bool prime[MAX];
memset(prime, sizeof(prime), true);
for(int i=4;i<MAX;i+=2) prime[i] = false;
prime[1] = false;
cout<<2<<" is prime\n";
for(int i=3;i*i<MAX;i+=2)
    if (prime[i]) {
        cout<<i<<" is prime\n";
        for(int j=i*i;j<MAX;j+=i)
            prime[j] = false;
    }

界限也值得注意。 i*i<MAXj > i/j快很多,而且您也不需要标记任何数字&lt;我*我,因为它们已经被标记,如果它们是复合的。最重要的是time complexity

3)如果你真的想快速制作这个算法,你需要缓存优化它。我们的想法是首先找到所有素数&lt; sqrt(MAX)然后用它们来查找剩下的部分 素数。然后你可以使用相同的内存块来查找1024-2047的所有素数,比方说, 然后是2048-3071。这意味着所有内容都将保存在L1缓存中。我曾经通过在Eratosthenes的筛子上使用这种优化来测量~12次加速。

您也可以通过不存储偶数来减少空间使用量,这意味着 您不必经常执行计算以开始处理新块。

如果你是初学者,你应该暂时忘记缓存。

答案 3 :(得分:0)

我们在这里发布的一大堆文字的一个简单答案是:审判部门! 如果有人提到这项任务所依据的数学基础,我们将节省大量时间;)

答案 4 :(得分:0)

#include <stdio.h>
#define N 1000

int main()
{

    bool primes[N];
    for(int i = 0 ; i < N ; i++) primes[i] = false;
    primes[2] = true;

    for(int i = 3 ; i < N ; i+=2) {   // Check only odd integers    
        bool isPrime = true;    
        for(int j = i/2 ; j > 2 ; j-=2) {    // Check only from largest possible multiple of current number  
            if ( j%2 == 0 ) { j = j-1; } // Check only with previous odd divisors
            if(!primes[j]) continue;     // Check only with previous prime divisors
            if ( i % j == 0 ) {             
                isPrime = false;
                break;
            }
        }
        primes[i] = isPrime;
    }

    return 0;
}

这是有效的代码。我还包括了之前海报中提到的许多优化。如果还有其他任何可以完成的优化,那么知道它将会提供信息。

答案 5 :(得分:0)

此功能可以更有效地查看数字是否为素数。

bool isprime(const unsigned long n)
{
 if (n<2) return false;
 if (n<4) return true; 
 if (n%2==0) return false;
 if (n%3==0) return false;
 unsigned long r = (unsigned long) sqrt(n);
 r++;
 for(unsigned long c=6; c<=r; c+=6)
 {
  if (n%(c-1)==0) return false;
  if (n%(c+1)==0) return false;
 }