2

現在、プログラミングスキルを練習するためだけに、いくつかの質問を試しています。(学校などでまだ取っていません、独学です)この問題に遭遇したため、特定のtxtファイルから数値を読み取る必要がありました。この数は N になります。ここで、N <= 10 000 の N 番目の素数を見つけるとします。見つけたら、それを別の txt ファイルに出力するとします。これで、質問のほとんどの部分で、N を取得する方法を理解し、考案することができました。問題は、配列を使用して以前に見つかった素数を保存し、それらを使用して将来の数と照合することです。配列のサイズが 100 の場合でも、入力整数がおおよそ < 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ファイルを使用することを考えています。それは可能ですか?どんな助けでも大歓迎です。

4

14 に答える 14

16

あなたの質問は数学ではなくプログラミングに関するものなので、私もそのように答えようとします.

あなたのコードを一目見ただけで、ここで一体何をしているのだろうと思います...答えを読むと、コードを理解しようとしない人もいれば、コードをデバッガーにダンプするだけの人もいることに気付くでしょう。そして何が起こっているか見てください。私たちはそれほどせっかちなのですか?それとも、比較的簡単な問題に対してコードが難しすぎて理解できないだけですか?

コードを改善するには、次の質問を自問してみてください。

  1. ab、などとは何cですか? もっと意味のある名前を付けたほうがいいのではないでしょうか?
  2. あなたのアルゴリズムは正確には何ですか?あなたがしていることについて、英語で明確に書かれた段落を(正確に)書き留めることができますか?パラグラフを一連のステップに変更して、任意の入力に対して精神的に実行でき、それが正しいことを確認できますか?
  3. すべての手順が必要ですか? それらのいくつかを組み合わせたり、削除したりすることはできますか?
  4. 英語で表現するのは簡単ですが、C/C++ では 10 行以上必要な手順は何ですか?
  5. ステップのリストに何らかの構造がありますか? ループ?サブステップを含む単一のステップとして配置できる大きな (おそらく繰り返される) チャンク?

質問に答えた後は、問題を解決する明確にレイアウトされた疑似コードが得られるでしょう。これは、説明と理解が容易です。その後、疑似コードを C/C++、または実際には任意の汎用言語で実装できます。

于 2009-02-02T08:22:54.607 に答える
1

私はあなたのコードを見ていませんが、あなたの配列はあなたがそれに保存するすべての値を含むのに十分な大きさでなければなりません。この問題のほとんどの入力には、100では確かに十分ではありません。

たとえば、このコード。

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

配列よりも大きい場所(150> 100)に書き込みます。これは、メモリの上書きと呼ばれます。そのメモリ位置に何が起こったかに応じて、プログラムはすぐに、後で、またはまったくクラッシュしない可能性があります。

配列を使用する場合の良い習慣は、書き込み先の要素が配列の範囲内にあることを何らかの方法で表明することです。または、このチェックを実行する配列型クラスを使用します。

問題の場合、最も簡単なアプローチはSTLベクトルクラスを使用することです。要素を追加する必要がありますが(vector :: push_back())、後で配列演算子[]を使用して要素にアクセスできます。ベクターはまた、最高の反復パフォーマンスを提供します。

これは、0から100までの数字をベクトルに追加し、それらを出力するサンプルコードです。2番目のループでは、ベクトルに格納されているアイテムの数を使用していることに注意してください。

#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);
}
于 2009-02-02T07:49:10.163 に答える
1

考慮したい素数性をテストするには、2つのアプローチがあります。

  1. 問題のドメインは十分に小さいので、N番目の素数が見つかるまで数値をループするだけで、おそらく許容できる解決策になり、完了するまでに数ミリ秒もかかりません。このアプローチにはいくつかの簡単な最適化を行うことができます。たとえば、2で割り切れるかどうかをテストするだけで、奇数をチェックするだけで、以下の数をチェックするだけで済みます。テストされている数のアクアルートに。
  2. エラトステネスのふるいは非常に効果的で実装が簡単で、数学の終わりを信じられないほど軽くします。

コードがクラッシュする理由については、次の行を変更しているのではないかと思います。

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

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

おそらくガベージを含む配列の初期化されていない可能性のある要素から読み取ろうとしているため、問題が修正されます。

于 2009-02-02T07:50:18.727 に答える
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;
    }
}
于 2011-06-30T13:55:25.603 に答える
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;
}

ちなみに、これを改善する方法についてのアドバイスは大歓迎です。

于 2009-02-02T10:22:25.283 に答える
0

これは教育目的であるため、エラトステネスのふるいを実装することをお勧めします。

于 2009-02-02T07:44:24.823 に答える
0

1つは、3、5、および7の特別なケースがなければ、コードが少なくなることです(これは常に良いことです!)。

また、num [b] = 2に設定し、配列内の除算のみをテストする場合は、2の特殊なケースを回避できます。

于 2009-02-02T07:50:25.200 に答える
0

メインのfor()ループを回ると、bの値が増加するように見えます。

次に、配列の端からメモリにアクセスするため、クラッシュが発生します。

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

アルゴリズムを頭の中で明確にしてから、コードに再度アプローチする必要があると思います。

于 2009-02-02T07:52:16.790 に答える
0

デバッガーを介してコードを実行すると、「」で浮動小数点例外が発生してクラッシュすることがわかりましたif ((a % c) == 0)。これは、numで何も初期化していないため、「a%0」を実行しているためです。

于 2009-02-02T07:53:29.547 に答える
0

私の知る限り、C / C ++ではintは16ビット型であるため、100万を収めることはできません(制限は2 ^ 16 = 32kです)。「a」を宣言してみてください

intC規格では、少なくともと同じくらいの大きさshortで、せいぜいと同じくらいの大きさであると言っていると思いますlong

実際intには4バイトなので、-2^31との間の数値を保持でき2^31-1ます。

于 2009-02-02T07:55:59.947 に答える
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;
}

これは私の元のコードに基づいた最終版です。これは完全に機能し、素数の範囲を増やしたい場合は、配列番号を増やすだけです。助けてくれてありがとう=)

于 2009-02-02T15:15:29.203 に答える
0

これも興味深いはずです: http://en.wikipedia.org/wiki/Primality_test

于 2009-02-02T08:19:14.333 に答える
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.

アドバイスをありがとうポリシンカー=)

于 2009-02-02T10:22:40.667 に答える
0

後の質問ではより大きな素数の値が必要になるため、ドリーブスのアドバイスに従い、ふるい分けを行うことをお勧めします。矢筒に入れておくととても便利な矢です。

于 2009-02-02T16:04:40.290 に答える