简体   繁体   English

C++ 素数从 3 到 n

[英]C++ Prime Numbers from 3 to n

I wrote this code to print all prime numbers between 3 and 'n' inputted by the user, but upon running, it produces nothing.我编写了这段代码来打印用户输入的 3 到 'n' 之间的所有素数,但是在运行时,它什么也没产生。

Can you please help?你能帮忙吗?

#include <iostream>
using namespace std;

int main()
{
    int n;
    cin >> n;

    for (int candidate = 3; candidate < n; ++candidate)
    {
        bool isPrime = true;
        for (int x = 2; x < n; x++)
        {
            if (candidate % x == 0)
            {
                isPrime = false;
            }
        }

        if (isPrime)
        {
            cout << n << "";
        }
    }
}

One thing you should know.你应该知道的一件事。 For checking whether n is prime if we start checking by division operation then you shouldn't check more than sqrt(n) .如果我们开始通过除法运算来检查 n 是否为素数,那么检查的次数不应超过sqrt(n)

    for (int candidate = 3; candidate < n; ++candidate)
    {
        bool isPrime = true;
        for (int x = 2; x*x < candidate; x++)
        {
            if (candidate % x == 0)
            {
                isPrime = false;
                break;
            }
        }

        if (isPrime)
        {
            cout << candidate << "";
        }
    }

Better way is to use Sieve of Eratosthenes for this:更好的方法是使用Eratosthenes 筛法

isPrime: initialize with all true
for(int i=2;i*i<=n;i++)
  for(int j =i*i;j<=n;j+=i)
    isPrime[j]=false;   // the if was not needed.

Now you know which are primes between 3 and n .现在您知道哪些是 3 和n之间的素数。

There are several efficiency savings possible in your code.在您的代码中可以节省一些效率。 The most efficient method (apart from using a pre-calculated look-up table for small (<1000) n ) is the sieve of Erastosthenes .最有效的方法(除了对小 (<1000) n使用预先计算的查找表)是Erastosthenes筛法

A very naive version of this algorithm (see also the answer by coderredoc )该算法的一个非常幼稚的版本(另请参阅coderredoc答案

std::vector<int> primes(int n)
{
    std::vector<bool> is_prime(n+1,true);
    for(auto divisor=2; divisor*divisor <= n; ++divisor)
        for(auto candidate=divisor*divisor; candidate <= n; candidate+=divisor)
            is_prime[candidate]=false;
    std::vector<int> result;
    for(auto candidate=2; candidate <= n; ++candidate)
        if(is_prime[candidate]) result.push_back(candidate);
    return result;
}

essentially reverses the loops over candidate s and divisor s compared to your original algorithm, but only tests for divisor s satisfying divisor*divisor<=candidate .与您的原始算法相比,本质上反转了candidate s 和divisor s 上的循环,但仅测试满足divisor*divisor<=candidate divisor s。

This algorithm can be substantially improved by realizing that we only need to test for prime divisors (which is the main trick of the sieve)通过意识到我们只需要测试素数除数(这是筛法的主要技巧),可以大大改进该算法

std::vector<int> primes(int n)
{
    std::vector<bool> is_prime(n+1,true);
    for(auto divisor=2; divisor*divisor <= n; ++divisor)
        if(is_prime[divisor])
            for(auto candidate=divisor*divisor; candidate <= n; candidate+=divisor)
                is_prime[candidate]=false;
    std::vector<int> result;
    for(auto candidate=2; candidate <= n; ++candidate)
        if(is_prime[candidate]) result.push_back(candidate);
    return result;
}

which cuts down on the testing for large n .这减少了对大n的测试。 A further efficiency saving (by a factor ~2 in space and time) is possible by avoiding even candidate s and divisor s:通过避免偶数candidate s 和divisor s,可以进一步提高效率(空间和时间上的约 2 倍):

std::vector<int> primes(int n)
{
    if(n<2) return {};
    if(n==2) return {2};
    std::vector<bool> is_prime((n+1)>>1,true);
    for(auto divisor=3; divisor*divisor <= n; divisor+=2)
        if(is_prime[divisor>>1])
            for(auto candidate=divisor*divisor; candidate <= n; candidate+=2*divisor)
                is_prime[candidate>>1]=false;
    std::vector<int> result(1,2);
    for(auto candidate=3; candidate <= n; candidate+=2)
        if(is_prime[candidate>>1]) result.push_back(candidate);
    return result;
}

This algorithm has a poor memory access pattern (into the is_prime[] ), which becomes a problem for very large n .该算法具有较差的内存访问模式(进入is_prime[] ),这对于非常大的n成为一个问题。 A more sophisticated method, segmented sieve , can avoid that, see the above link.一种更复杂的方法,分段筛,可以避免这种情况,请参阅上面的链接。

Change your inner loop from改变你的内循环

    for (int x = 2; x < n; x++)
    {
        if (candidate % x == 0)
        {
            isPrime = false;
        }
    }

to

    for (int x = 2; x < candidate; x++)
    {
        if (candidate % x == 0)
        {
            isPrime = false;
            break;
        }
    }

otherwise x would eventually become candidate itself and candidate%candidate is 0 which would cause isPrime to become false .否则x最终将成为candidate本身,而candidate%candidate0 ,这将导致isPrime变为false

The break statement is used because after being sure that the number is not prime, there's no need of further iterations.使用break语句是因为在确定数字不是素数之后,就不需要进一步的迭代了。

And since you consider only numbers from 3 , you could change your outer loop to save some iterations like而且由于您只考虑3数字,因此您可以更改外循环以保存一些迭代,例如

for (int candidate = 3; candidate < n; candidate+=2)

This would increment candidate by 2 each time.这将使candidate每次增加2 This is okay because no even numbers greater than 2 are not prime.这是可以的,因为没有大于 2 的偶数不是素数。

Also, if the range of numbers you are considering is inclusive of n , you may modify the outer for loop to此外,如果您考虑的数字范围包含n ,您可以将外部 for 循环修改为

for (int candidate = 3; candidate < n; candidate+=2)

to consider n as well.还要考虑n

  1. It's not recommended to use using namespace std;不推荐使用 using namespace std; — because this imports all of the identifiers from std. — 因为这会从 std 中导入所有标识符。 See this question on Stack Overflow .请参阅Stack Overflow上的这个问题。

  2. Should the end condition of the second loop be candidate instead of n , ie第二个循环的结束条件是否应该是candidate而不是n ,即

    for (int x = 2; x < candidate; x++)//not before N prime numbers divine up to them { if (candidate % x == 0) isPrime = false; }
  3. Shouldn't you put out candidate instead of n你不应该推出candidate而不是n

I think this should work我认为这应该有效

#include <iostream>
#include <vector>


int main()
{
    //setup start parameters
    //test sequence
    std::vector<int> test_sequence {2};




    int end_number, start_number;
    start_number = 3;
    //take wished end number
    std::cin >> end_number;

    // test is wished number smaler than start number
    if (start_number < end_number)
    {
        // loop which goes trough every number between start and end number
        for (start_number; start_number <= end_number; start_number++)
        {
            bool isPrime = true;
            //test is this number prime
            for (int n = 0; n < test_sequence.size(); n++)
            {
                if (start_number % test_sequence[n] == 0 && start_number != test_sequence[n] )
                {
                isPrime = false;
                }
            }

            if (isPrime)
            {
                std::cout << start_number << std::endl;
                //hold result for next test
                test_sequence.push_back(start_number);
            }
        }

    }
    else
    {
    std::cout << "Wrong input";
    }

}

Result for first 200前 200 名的结果

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM