Программа простых чисел - PullRequest
       48

Программа простых чисел

2 голосов
/ 02 февраля 2009

В настоящее время я пробую ответить на несколько вопросов, чтобы попрактиковаться в своих навыках программирования. (Пока не брал его в школу или что-то еще, самоучка) Я столкнулся с этой проблемой, которая требовала, чтобы я прочитал число из заданного текстового файла. Это число будет равно N. Теперь я предполагаю найти N-е простое число для N <= 10 000. После того, как я его найду, я предполагаю распечатать его в другой текстовый файл. Теперь для большинства частей вопроса я могу понять и разработать метод получения N. Проблема в том, что я использую массив для сохранения ранее найденных простых чисел, чтобы использовать их для проверки будущих чисел. Даже когда мой массив был размером 100, при условии, что входное целое число было примерно <15, программа зависала. </p>

#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 ]

16 голосов
/ 02 февраля 2009

Поскольку ваш вопрос касается программирования, а не математики, я постараюсь сохранить свой ответ таким же образом.

Первый взгляд на ваш код заставляет меня задуматься, что же вы здесь делаете ... Если вы прочитаете ответы, вы поймете, что некоторые из них не удосужились понять ваш код, а некоторые просто выбросили ваш код к отладчику и посмотрим, что происходит. Неужели мы так нетерпеливы? Или просто ваш код слишком сложен для понимания относительно простой проблемы?

Чтобы улучшить свой код, попробуйте задать себе несколько вопросов:

  1. Что такое a, b, c и т. Д.? Не лучше ли дать более значимые имена?
  2. Какой именно у вас алгоритм? Можете ли вы написать четко написанный абзац на английском языке о том, что вы делаете (точно)? Можете ли вы преобразовать абзац в серию шагов, которые вы можете мысленно выполнить для любого ввода, и можете быть уверены, что он правильный?
  3. Все ли шаги необходимы? Можем ли мы объединить или даже устранить некоторые из них?
  4. Какие шаги легко выразить на английском языке, но требуют, скажем, более 10 строк в C / C ++?
  5. Есть ли в вашем списке шагов какие-либо структуры? Loops? Большие (возможно, повторяющиеся) куски, которые можно поместить как один шаг с подэтапами?

После того, как вы пройдете через вопросы, у вас, вероятно, будет четко изложенный псевдокод, решающий проблему, который легко объяснить и понять. После этого вы можете реализовать свой псевдокод на C / C ++ или, фактически, на любом языке общего назначения.

1 голос
/ 30 июня 2011

Вот мой код. При работе с большим числом это очень медленно! Он может вычислить все простые числа с введенным вами числом!

#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;
    }
}
1 голос
/ 02 февраля 2009

Сейчас я пытаюсь улучшить свое функциональное программирование, поэтому я просто быстро закодировал сито. Я полагаю, я выложу это здесь. Если вы все еще учитесь, вам это тоже может быть интересно.

#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;
}

Кстати, любые советы о том, как это улучшить, будут приветствоваться.

1 голос
/ 02 февраля 2009

Существует два подхода к проверке на простоту, которые вы можете рассмотреть:

  1. Проблемная область достаточно мала, так что простое циклическое переключение чисел до тех пор, пока вы не найдете N-е простое число, вероятно, будет приемлемым решением, и для его завершения потребуется менее нескольких миллисекунд. Существует несколько простых оптимизаций, которые вы можете внести в этот подход, например, вам нужно только проверить, делится ли он на 2 один раз, а затем вам нужно только проверить нечетные числа, и вам нужно только проверить числа, меньшие или равные в квадратный корень тестируемого числа.
  2. Сито Эратосфена очень эффективно, легко реализуемо и невероятно легко для математических целей.

Что касается того, почему ваш код не работает, я подозреваю, что изменилась строка, которая читает

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

до

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

исправит проблему, потому что вы пытаетесь читать из потенциально неинициализированного элемента массива, который, вероятно, содержит мусор.

1 голос
/ 02 февраля 2009

Я не смотрел на ваш код, но ваш массив должен быть достаточно большим, чтобы содержать все значения, которые вы будете хранить в нем. 100, безусловно, не будет достаточно для большинства входных данных для этой проблемы.

например. этот код ..

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);
}
0 голосов
/ 02 февраля 2009

Поскольку вам понадобятся большие значения простых чисел для последующих вопросов , я советую вам следовать советам гномов и сделать сито. Это очень полезная стрела в вашем колчане.

0 голосов
/ 02 февраля 2009
#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;
}

Это окончательная версия базы моего исходного кода. Он отлично работает, и если вы хотите увеличить диапазон простых чисел, просто увеличьте номер массива. Спасибо за помощь =)

0 голосов
/ 02 февраля 2009
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.

Спасибо за совет, политик, =)

0 голосов
/ 02 февраля 2009

Это также должно вас заинтересовать: http://en.wikipedia.org/wiki/Primality_test

0 голосов
/ 02 февраля 2009

Из того, что я знаю, в C / C ++ int - это 16-битный тип, поэтому вы не можете уместить в нем 1 миллион (ограничение составляет 2 ^ 16 = 32k). Попробуйте и объявите "а" как долго

Я думаю, что в стандарте C сказано, что int, по крайней мере, равен short и, самое большее, long.

На практике int - это 4 байта, поэтому он может содержать числа от -2^31 до 2^31-1.

...