【问题标题】:Efficiency of a prime number finding program(c++)素数查找程序的效率(c++)
【发布时间】:2022-10-14 14:46:53
【问题描述】:

我想知道我制作的这段代码是否效率低下,或者是否有更快的方法来查找素数。

#include <stdio.h>

int main(void)
{
    int count;

    for(int i=3; i<1000; i+=2){//search number in range of 3~999
        count=0;//init count
        for(int j=3; j*j<=i; j+=2){
            if(count==1){//if i has aliquot already, break the loop
                break;
            }
            if(i%j==0){
                count=1;//if i has aliquot, change count to 1
            }
        }
        if(count==0){
            printf("%d ", i);//if there are no aliquot, print i
        }
    }

    return 0;
}

【问题讨论】:

  • 我认为这是找到素数的最糟糕的方法之一。对于一些简单的事情,最好从实现埃拉托色尼筛或一个米勒·拉宾初试。
  • 每个小于 1000 的素数都可以通过仅查看 <32 的因数来找到,即最多 sqrt(1000)。
  • here 是打印 prims 小于 1000 的最有效方法。
  • 从 1 到 4000000000 只有大约 2 亿个素数,并且您使用的是 32 位整数,因此您可以预先计算并在 RAM 延迟时从 LUT 获得结果。
  • 仅使用2 作为见证,Miller Rabin 素数测试可以找到小于 1000 的素数。任何高达 MAX_INT 的内容只需要 3 或 4 个见证人 iirc。如果您只需要测试少量数字,这可能是最快的测试。如果您想将它们全部打印出来或测试数百万,那么筛子是最好的。

标签: c++ primes


【解决方案1】:

似乎您正在使用trial division,这需要(√n) 时间来确定单个数字的素数,因此在查找范围内的所有素数时效率低下。要有效地查找范围内的所有素数,请考虑使用sieve of Eratosthenes(具有时间复杂度(n日志n日志日志n)) 或Euler's sieve(具有时间复杂度(n))。以下是这两种算法的简单实现。

埃拉托色尼筛的实施

bool isPrime[N];

void eratosthenes(int n) {
    for (int i = 2; i <= n; ++i) {
        isPrime[i] = true;
    }
    isPrime[1] = false;
    for (int i = 2; i * i <= n; ++i) {
        if (isPrime[i]) {
            for (int j = i * i; j <= n; j += i) {
                isPrime[j] = false;
            }
        }
    }
}

欧拉筛的实现

bool isPrime[N];
std::vector<int> primes;

void euler(int n) {
    for (int i = 2; i <= n; ++i) {
        isPrime[i] = true;
    }
    isPrime[1] = false;
    for (int i = 2; i <= n; ++i) {
        if (isPrime[i]) primes.push_back(i);
        for (size_t j = 0; j < primes.size() && i * primes[j] <= n; ++j) {
            isPrime[i * primes[j]] = false;
            if (i % primes[j] == 0) break;
        }
    }
}

【讨论】:

  • 在筛子中从等式中取出 2 作为特殊情况。然后你只需要处理奇数。您的数组可以是一半大小,并且您的循环每次可以增加 2 步。
  • 为什么?您永远不会测试isPrime[i] 的偶数,因此它们是否在筛子中标记是无关紧要的。只需要标记奇数倍的素数。
【解决方案2】:

Eratosthenes Sieve 很酷,但已弃用?为什么不使用我的 Prime 课程?它有一个增量方法,不使用除法。 素数类通过其与较低素数的全等来描述一个数字。增加一个素数是为了增加所有同余,如果整数是素数,则创建一个新同余(所有同余-模_-不同于0)。

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>

class Prime {
public :
  Prime () : n_ (2), modulos_ (std::vector<std::pair<int, int> > ())
  {
    if (!modulos_.capacity ()) modulos_.reserve (100000000);
    std::pair<int, int> p (2, 0);
    modulos_.push_back (p);
  }
  ~Prime () {}
  Prime (const Prime& i) : n_ (i.n_), modulos_ (i.modulos_)
   {}
  bool operator == (const Prime& n) const {
    return (n_ == n.n_);
  }
  bool operator != (const Prime& n) const {
    return !operator == (n);
  }
  Prime& operator = (const Prime& i) {
    n_ = i.n_,
    modulos_ = i.modulos_;
    return *this;
  }
  void write (std::ostream& os) const {
    os << n_;
  }
  void operator ++ () {
    int prime (1);
    do {
      ++n_;
      prime = 1;
      std::for_each (modulos_.begin (), modulos_.end (), [&prime] (std::pair<int, int>& p) {
        ++p.second;
        if (p.first == p.second) {
          p.second = 0;
          prime  = 0;
        }
      });
    }
    while (!prime);
    std::pair<int, int> p (n_, 0);
    modulos_.push_back (p);
  }
  bool operator < (const int& s) const {
    return n_ < s;
  }
private :
  int n_;
  std::vector<std::pair<int, int> > modulos_; 
};

用法 :

int main (int, char**) {
  Prime p;
  do {
    p.write (std::cout);
    std::cout << std::endl;
    ++p;
  }
  while (p < 20);
}

结果 : 2 3 5 7 11 13 17 19

【讨论】:

    【解决方案3】:

    对于高达 1000 的素数,一种有效的方法是

    cout << "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  101 103 107 109
    113 127 131 137 139 149 151 157 163 167
    173 179 181 191 193 197 199 211 223 227
    229 233 239 241 251 257 263 269 271 277
    281 283 293 307 311 313 317 331 337 347
    349 353 359 367 373 379 383 389 397 401
    409 419 421 431 433 439 443 449 457 461
    463 467 479 487 491 499 503 509 521 523
    541 547 557 563 569 571 577 587 593 599
    601 607 613 617 619 631 641 643 647 653
    659 661 673 677 683 691 701 709 719 727
    733 739 743 751 757 761 769 773 787 797
    809 811 821 823 827 829 839 853 857 859
    863 877 881 883 887 907 911 919 929 937
    941 947 953 967 971 977 983 991 997" << endl;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多