【问题标题】:Optimizing prime numbers code?优化素数代码?
【发布时间】:2011-11-28 21:03:03
【问题描述】:

我写这段代码是为了显示 1 到 100 之间的素数。唯一的条件是不要使用函数,整个代码应该是内联的。我想问我是否可以进一步改进(优化)它?

#include<iostream>

using namespace std;

int main() {

    int i=2,j=2;

    cout<<"Prime numbers between 1 and 100 are:"<<endl;
    cout<<"2"<<"\t";
    while(i!=100) {
        for(int j=2;j<i;j++) {
            if(i%j==0)
            break;

            if(j==i-1)
            cout<<i<<"\t";
        }

        i++;
    }

    cout<<endl;
    system("pause");
    return 0;
}

【问题讨论】:

  • "唯一的条件是不要使用函数,整个代码应该是内联的。"为什么不编写函数然后打开编译器优化,以便为您内联它们?两全其美。
  • 你只需要检查直到j &lt;= sqrt(i)。
  • 您只需要检查奇数。没有可以被偶数整除的素数(除了 2),因此您可以将 j++ 替换为 j=j+2 以将搜索时间缩短一半。
  • 如果这是作业,请添加作业标签!
  • 在这种情况下优化是什么意思?

标签: c++ primes


【解决方案1】:
    for(int j=2;j<i;j++){

这个不好看。

首先,你只需要检查j &lt;= sqrt(i),例如7永远不会不休息就除掉12。

其次,您应该跟踪所有以前找到的素数;将它保存在向量中,并且只针对它的内容执行此循环和对于我写的那个条件。

【讨论】:

  • 他可以停在平方根,而不是半数。
  • 你必须做一些事情来避免使用 sqrt 函数。
  • j*j&lt;i,但这确实节省了函数调用。
【解决方案2】:

您可以优化现有代码:

  • 在 while 循环中,步长应为 2,这样就不会测试偶数。
  • 在您的 for 循环中,当您达到要测试的数字的平方根时,您应该停止

您可以使用不同的方法:

在 Erastoses 筛上,仅删除可被 2,3 和 5 整除的数字将显着减少您需要测试素数的次数。

【讨论】:

    【解决方案3】:

    如果您只希望素数低于 100,则无需编写代码来计算它们。这可能是一个愚蠢的答案,但它可以有效而简洁地解决您的问题。

    int main() {
        cout << "Prime numbers are:" << endl << "2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97" << endl;
        return 0;
    }
    

    【讨论】:

    • 你没有抓住重点。素数本身并不是有趣的部分,算法才是。
    • 你对我的question也有什么解决办法吗?
    【解决方案4】:

    避免使用平方根函数,并将除数增加 2。还有一些棘手的事情在 i 循环中将可能的素数增加 2。内循环甚至不需要检查 2 的可除性,因为没有偶数会甚至被测试。

    int i,j,sq;
    int min;
    for(sq = 2; sq <= 10; sq++)
    {
      min = (sq-1)*(sq-1);
      min = min + (min+1)%2; //skip if it's even, so we always start on odd
      for(i = min; i < sq*sq; i+=2)
      {
        for(j = 3; j <= sq; j+=2)
        {
          if (i%j == 0)
            bad;
        }
      }
    }
    

    请注意,sq 循环不会增加时间,因为它会按比例缩小内部循环。

    【讨论】:

      【解决方案5】:

      您正在检查从 2 到 100 的每个数字。但由于 2 是唯一的偶素数,您可以跳过 2 之后的每个偶数。这适用于 i 和 j。所以从 3 开始 i 和 j,然后将它们增加 2。

      #include<iostream>
      
      using namespace std;
      
      int main() {
          cout<<"Prime numbers between 1 and 100 are:"<<endl;
          cout<<"2"<<"\t";
          for (int i=3; i<100;i+=2) {
              // This loop stops either when j*j>i or when i is divisible by j.
              // The first condition means prime, the second, not prime.
              int j=3;
              for(;j*j<=i && i%j!=0; j+=2); // No loop body
      
              if (j*j>i) cout << i << "\t";
          }
          cout<<endl;
          return 0;
      }
      

      除了上面提到的技巧之外,我还添加了条件j*j&lt;=i,它在逻辑上与j&lt;=sqrt(i) 完全相同。如果可以进行简单的乘法运算,则无需计算平方根。

      【讨论】:

      • 我认为将j 增加 2 是不正确的!
      • @Adban:是的。奇数不能被偶数整除。
      • 有没有办法告诉编译展开循环?
      【解决方案6】:

      取决于您要进行的优化。你的尽可能好,我可以看到你是否首先优化空间,其次是时间(嗯,接近 - 只要你听@Paul,它就会)。如果您颠倒优先级,Erastothenes 筛子会更快(但会占用您 100 个布尔值)。

      【讨论】:

      • 如果您想真正了解节省内存,您可以使用 100 个一位位域,这将节省大量内存。 :) 顺便说一句,他可以做一件事:他可以在j &lt;= sqrt(i) 停下来。
      • :) 是的,我已经更正了。接得好。位域仍然是布尔值,概念上 :P 并且处理位域会减慢您的速度,因此如果您的目标是速度,您可能会使用 100 个字节。
      【解决方案7】:

      你可以做两个简单的优化:

      cout << 2 << '\t';
      for (int i = 3; i <= 100; ++i) {
          for (int j = 3, l = (int)sqrt(i); j <= l; j += 2) {
              if (i % j == 0) {
                  cout << i << '\t';
                  break;
              } 
      } 
      

      我做了什么:

      数学:

      • 在j &gt; sqrt(i) 时停止,没有必要走得更远。但是请注意,sqrt 是一个昂贵的函数;对于您的小样本(从 1 到 100),使用它可能(阅读,肯定会)花费更多。
      • 只检查奇数;做j += 2 而不是一个一个递增j

      微优化:

      • 使用++i 代替i++;后者有一个临时变量,它存储i 的原始值;前者没有。
      • 将'\t' 打印为字符而不是字符串"\t"。

      (无论如何,这些微优化可能是编译器自动进行的,但了解它们并没有什么坏处。)

      【讨论】:

      • 他不能使用 sqrt 函数
      【解决方案8】:

      实现这一目标的最有效方法是埃拉托色尼筛。这是一个增量版本,专门用于生成最多 100 的素数,一个一个(最大到 120,因为 121 == 11 * 11 em>)。

      int m3 = 9, m5 = 25, m7 = 49, i = 3;
      printf("2 ");
      for( ; i < 100; i += 2 )
      {
          if( i != m3 && i != m5 && i != m7)
              printf("%d ", i);
          else
          {
              if( i == m3 ) m3 += 6;
              if( i == m5 ) m5 += 10;
              if( i == m7 ) m7 += 14;
          }
      }
      

      【讨论】:

        【解决方案9】:
        /*** Return an array of primes from 2 to n. ***/
        int[] function nPrimes(int n) {
           int primes[];  //memory allocation may be necessary depending upon language.
           int p = 0;
           bool prime;
           for (int i = 2; i <= n; i++) {
               prime = true;
               //use (j <= (int)sqrt(i)) instead of (j < i) for cost savings.
               for (int j = 2; j <= (int)sqrt(i); j++)  {
                   if (i % j == 0) {
                       prime = false;
                       break;
                   }
               }
               if (prime) {
                   primes[p++] = i;
               }    
           }
           return primes;
        }
        

        【讨论】:

        • 您能否提供您的代码的快速摘要。我知道它在做什么,但它会帮助更广泛的受众了解你具体做了什么。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-23
        • 1970-01-01
        • 2018-05-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多