素数计划

时间:2009-02-02 07:29:18

标签: c++ primes

我正在尝试一些问题,只是为了练习我的编程技巧。 (没有把它带到学校或其他任何东西,自学)我遇到了这个问题,要求我从给定的txt文件中读取一个数字。这个数字是N.现在我想找到N <= 10 000的第N个素数。在找到之后,我想把它打印到另一个txt文件。现在对于问题的大部分内容,我能够理解并设计一种方法来获得N.问题是我使用数组来保存以前找到的素数,以便用它们来检查未来的数字。即使我的数组大小为100,只要输入整数大致为&lt; 15,程序崩溃。

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;

int main() {
    ifstream trial;
    trial.open("C:\\Users\\User\\Documents\\trial.txt");
    int prime;
    trial >> prime;
    ofstream write;
    write.open("C:\\Users\\User\\Documents\\answer.txt");
    int num[100], b, c, e;
    bool check;
    b = 0;
    switch (prime) {
        case 1:
        {
            write << 2 << endl;
            break;
        }
        case 2:
        {
            write << 3 << endl;
            break;
        }
        case 3:
        {
            write << 5 << endl;
            break;
        }
        case 4:
        {
            write << 7 << endl;
            break;
        }
        default:
        {
            for (int a = 10; a <= 1000000; a++) {
                check = false;
                if (((a % 2) != 0) && ((a % 3) != 0) && ((a % 5) != 0) && ((a % 7) != 0)) // first filter
                {
                    for (int d = 0; d <= b; d++) {
                        c = num[d];
                        if ((a % c) == 0) {
                            check = true; // second filter based on previous recorded primes in array
                            break;
                        }

                    }
                    if (!check) {
                        e = a;
                        if (b <= 100) {
                            num[b] = a;
                        }

                        b = b + 1;
                    }
                }
                if ((b) == (prime - 4)) {
                    write << e << endl;
                    break;
                }
            }
        }
    }
    trial.close();
    write.close();
    return 0;
}

我完全基于我的假人指南和我自己这样做,所以请原谅我的算法的一些代码效率低下和一般新手。 此外,对于最多15个,它会正确显示素数。

有人能告诉我如何改进当前的代码吗?我正在考虑使用txt文件代替数组。那可能吗?任何帮助表示赞赏。

14 个答案:

答案 0 :(得分:16)

由于你的问题是关于编程而不是数学,我会尽力保持我的答案。

你的代码的第一眼让我想知道你在这里做了什么...如果你读了答案,你会发现其中一些人不愿意理解你的代码,有些只是转储你的代码到调试器,看看发生了什么。难道我们不耐烦吗?或者仅仅是因为相对容易的问题,您的代码难以理解?

要改进您的代码,请尝试自问一些问题:

  1. 什么是abc等?提供更有意义的名字不是更好吗?
  2. 你的算法究竟是什么?你能用英文写下一个清楚写的段落,说明你在做什么(以一种确切的方式)?您是否可以将段落修改为一系列步骤,您可以在任何输入上进行精神上的操作,并确保它是正确的?
  3. 是否所有步骤都必要?我们可以合并甚至消除其中一些吗?
  4. 在英语中易于表达的步骤有哪些,但在C / C ++中需要超过10行?
  5. 您的步骤列表是否有任何结构?循环?大的(可能是重复的)块可以通过子步骤单步执行吗?
  6. 在完成问题之后,您可能会有一个清晰的伪代码来解决问题,这很容易解释和理解。之后,您可以在C / C ++中实现伪代码,或者实际上是任何通用语言。

答案 1 :(得分:1)

我没有看过你的代码,但你的数组必须足够大,以包含你将存储在其中的所有值。对于这个问题,100肯定不足以满足大多数输入。

E.g。这段代码..

int someArray[100];
someArray[150] = 10;

写入大于数组的位置(150> 100)。这称为内存覆盖。根据发生在该内存位置的情况,您的程序可能会立即崩溃,稍后或根本不会崩溃。

使用数组时的一个好习惯是在某种程度上断言你要写的元素在数组的范围内。或者使用执行此检查的数组类型。

对于您的问题,最简单的方法是使用STL向量类。虽然必须添加元素(vector :: push_back()),但您可以稍后使用数组运算符[]访问元素。 Vector还将为您提供最佳的迭代性能。

以下是将数字0-100添加到矢量然后打印它们的示例代码。请注意,在第二个循环中,我们使用向量中存储的项目数。

#include <vector> // std::vector

...

const int MAX_ITEMS = 100;

std::vector<int> intVector;

intVector.reserve(MAX_ITEMS); // allocates all memory up-front

// add items
for (int i = 0; i < MAX_ITEMS; i++)
{
  intVector.push_back(i);  // this is how you add a value to a vector;
}

// print them
for (int i = 0; i < intVector.size(); i++)
{
  int elem = intVector[i]; // this access the item at index 'i'
  printf("element %d is %d\n", i, elem);
}

答案 2 :(得分:1)

有两种方法可以测试你可能想要考虑的素数:

  1. 问题域足够小,只需循环遍历数字,直到找到Nth prime可能是一个可接受的解决方案,并且需要不到几毫秒的时间才能完成。您可以对此方法进行一些简单的优化,例如,您只需要测试它是否可被2整除,然后您只需检查奇数,您只需要检查小于或等于的数字到正在测试的数字的aquare根。
  2. The Sieve of Eratosthenes非常有效且易于实施,并且在数学方面非常轻松。
  3. 至于为什么你的代码崩溃我怀疑改变了读取的行

    for( int d=0; d<=b; d++) 
    

    for( int d=0; d<b; d++) 
    

    将修复此问题,因为您正在尝试从可能包含垃圾的数组的潜在未初始化元素中读取。

答案 3 :(得分:1)

我正在尝试改进我的功能编程,所以我只是快速编写了筛子。我想我会把它贴在这里。如果你还在学习,你也会发现它很有趣。

#include <iostream>
#include <list>
#include <math.h>
#include <functional>
#include <algorithm>

using namespace std;

class is_multiple : public binary_function<int, int, bool>
{
    public:
        bool operator()(int value, int test) const
        {
            if(value == test) // do not remove the first value
                return false;
            else
                return (value % test) == 0;
        }
};

int main() 
{
    list<int> numbersToTest;
    int input = 500;

    // add all numbers to list
    for(int x = 1; x < input; x++)
        numbersToTest.push_back(x);

    // starting at 2 go through the list and remove all multiples until you reach the squareroot
    // of the last element in the list
    for(list<int>::iterator itr = ++numbersToTest.begin(); *itr < sqrt((float) input); itr++)
    {
        int tmp = *itr;
        numbersToTest.remove_if(bind2nd(is_multiple(), *itr));  
        itr = find(numbersToTest.begin(), numbersToTest.end(), tmp); //remove_if invalidates iterator 
                                                                 // so find it again. kind of ugly
    }

    // output primes
    for(list<int>::iterator itr = numbersToTest.begin(); itr != --numbersToTest.end(); itr++)
        cout << *itr << "\t";

    system("PAUSE");

    return 0;
}

顺便说一句,有关如何改进这方面的任何建议都会受到欢迎。

答案 4 :(得分:1)

这是我的代码。在处理大数字时,它非常慢! 它可以用您输入的数字计算所有素数!

#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;

int main()
{
    int m;
    int n=0;
    char ch;
    fstream fp;
    cout<<"What prime numbers do you want get within?  ";
    if((cin>>m)==0)
    {
                 cout<<"Bad input! Please try again!\n";
                 return 1;
    }
    if(m<2)
    {
        cout<<"There are no prime numbers within "<<m<<endl;
        return 0;
    }
    else if(m==2)
    {
        fp.open("prime.txt",ios::in|ios::out|ios::trunc);//create a file can be writen and read. If the file exist, it will be overwriten.
        fp<<"There are only 1 prime number within 2.\n";
        fp<<"2\n";
        fp.close();
        cout<<"Congratulations! It has worked out!\n";
        return 0;
    }
    else
    {
        int j;
        int sq;
        fp.open("prime.txt",ios::in|ios::out|ios::trunc);
        fp<<"2\t\t";
        n++;
        for(int i=3;i<=m;i+=2)
        {
            sq=static_cast<int>(sqrt(i))+1;
            fp.seekg(0,ios::beg);
            fp>>j;
            for(;j<sq;)
            {
                if(i%j==0)
                {
                    break;
                }

                else
                {
                    if((fp>>j)==NULL)
                    {
                        j=3;
                    }
                }
            }
            if(j>=sq)
            {
                fp.seekg(0,ios::end);
                fp<<i<<"\t\t";
                n++;
                if(n%4==0)
                    fp<<'\n';
            }
        }
        fp.seekg(0,ios::end);
        fp<<"\nThere are "<<n<<" prime number within "<<m<<".\n";
        fp.close();
        cout<<"Congratulations! It has worked out!\n";
        return 0;
    }
}

答案 5 :(得分:0)

由于这是出于教学目的,我建议实施the Sieve of Eratosthenes

答案 6 :(得分:0)

首先,如果您没有3,5和7的特殊情况,那么您的代码就会减少(这总是一件好事!)。

另外,如果只设置num [b] = 2并且只测试数组中的事物的可分性,则可以避免2的特殊情况。

答案 7 :(得分:0)

看起来当你绕过主要的for()循环时,b的值会增加。

然后,这会导致崩溃,因为您访问了数组末尾的内存:

                for (int d = 0; d <= b; d++) {
                    c = num[d];

我认为您需要让算法更清晰,然后再次接近代码。

答案 8 :(得分:0)

通过调试器运行代码,我发现它在“if ((a % c) == 0)”处发生浮点异常崩溃。这样做的原因是你没有在num中初始化任何东西,所以你正在做“%0”。

答案 9 :(得分:0)

  

据我所知,在C / C ++中int是一个16位类型,所以你不能容纳100万(限制是2 ^ 16 = 32k)。尝试并声明“a”为

我认为C标准规定int至少与short一样大,最多与long一样大。

实际上,int是4个字节,因此它可以保存-2^312^31-1之间的数字。

答案 10 :(得分:0)

您也应该对此感兴趣:http://en.wikipedia.org/wiki/Primality_test

答案 11 :(得分:0)

for(int currentInt=2; currentInt<=1000000; currentInt++) 

{check = false;  // Basically the idea for this for loop is to run checks against integers. This is the main for loop in this program. I re initialize check to false ( check is a bool declared above this. )

for( int arrayPrime=0; arrayPrime<currentPrime; arrayPrime++) // This for loop is used for checking the currentInt against previously found primes which are stored in the num array.

{ c=num[arrayPrime];
        if ((currentInt%c)==0) { check = true;// second filter based on previous recorded primes in array
                break;}  // this is the check. I check the number against every stored value in the num array. If it's divisible by any of them, then bool check is set to true.


if ( currentInt == 2)
{ check = false; } // since i preset num[0] = 2 i make an exception for the number 2.

if (!check)
{
e=a;
if(currentPrime <= 100){
num[currentPrime]= currentInt;} // This if uses check to see if the currentInt is a prime. 

currentPrime = currentPrime+1;} // increases the value of currentPrime ( previously b ) by one if !check.

if(currentPrime==prime)
{
write<<e<<endl;
break;}           // if currentPrime == prime then write the currentInt into a txt file and break loop, ending the program.

感谢您的建议polythinker =)

答案 12 :(得分:0)

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <fstream>

using namespace std;

int main()
{
ifstream trial;
trial.open("C:\\Users\\User\\Documents\\trial.txt");
int prime, e;
trial>>prime;
ofstream write; 
write.open("C:\\Users\\User\\Documents\\answer.txt");
int num[10000], currentPrime, c, primePrint;
bool check;
currentPrime=0;
num[currentPrime] = 2;
currentPrime=1;

for(int currentInt=2; currentInt<=1000000; currentInt++) 
{check = false; 
for( int arrayPrime=0; arrayPrime<currentPrime; arrayPrime++) 
        { c=num[arrayPrime];
            if ((currentInt%c)==0) { check = true;// second filter based on previous recorded primes in array
                    break;}
               }


 if (!check)
    { e=currentInt;  
    if( currentInt!= 2 ) { 
    num[currentPrime]= currentInt;}
    currentPrime = currentPrime+1;}
    if(currentPrime==prime)
    {
    write<<e<<endl;
    break;}
    }
trial.close();
write.close();
return 0;
}

这是我原始代码的最终版本。它完美地工作,如果你想增加素数的范围,只需增加数组编号。谢谢你的帮助=)

答案 13 :(得分:0)

由于later questions需要更大的素数值,我建议您遵循Dreeves建议并进行筛选。它是你箭袋里非常有用的箭头。