Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » Optimierung einer Funktion um Primzahlen zu filtern

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ] [ 3 ]
000
17.12.2006, 13:36 Uhr
~Starsurfer
Gast


Moin C++`ler,

ich bin noch recht neu in C++ und versuche mich gerade an einem Programm was mir Primzahlen filtert,

das Berechnen funktioniert so weit(ich denk auch richtig..) nur die Funktion is mir zu langsam

Hier im Forum bin ich auf paar Programme gestoßen die aber endweder langsamer sind oder ganz anderst ablaufen als meine Version.

Testergenisse:
--------------
filtern+speichern

500000 Primzahlen -> ~2.6 sec
1000000 Primzahlen -> ~7.6 sec
10000000 Primzahlen -> ~244 sec

Intel Core Duo T2300 2*1,66Ghz

so nun zum Code:


C++:
//---------------------------------------------------------------------------

#include <iostream>
#include <windows>
#include <cmath>
using namespace std;
//---------------------------------------------------------------------------

int main()
{
        unsigned int akt_anzahl,ges_anzahl,akt_zahl;
        unsigned int *prim_liste; //dyn array für primzahlen
        unsigned int *akt_prim_adresse;  //zeiger auf element von prim array
        unsigned int *akt_zahl_adresse;  //zeiger auf akt_zahl
        bool ist_prim;
        LONGLONG frequenz, end_zeit, start_zeit;
        double TimeScale;

        cin >> ges_anzahl;

        if((prim_liste=(unsigned int *) malloc(sizeof(unsigned int)*ges_anzahl))==NULL)//dyn array erzeugen
        {
                cout << "Nicht genug Speicher fuer Array\n\n";
                system("Pause");
                return 0;
        }
        prim_liste[0]=2;        //erste prim zahl setzen
        akt_anzahl=1;           //start parameter setzen
        akt_zahl=3;             //
        akt_zahl_adresse=&akt_zahl;

        QueryPerformanceFrequency((LARGE_INTEGER*) &frequenz);  //system freq ermitteln
        QueryPerformanceCounter((LARGE_INTEGER*) &start_zeit);     //anfangszeit ermitteln
        TimeScale = 1.0/frequenz;
        //filtern
        do
        {
                akt_prim_adresse=&prim_liste[0];
                ist_prim=true;
                for(unsigned int i=1;i<akt_anzahl;i++)
                        {
                                akt_prim_adresse++;//zum nächsten array element
                                if((*akt_zahl_adresse)%(*akt_prim_adresse)==0) //sollte kein rest mehr bleiben, isses keine prim
                                {
                                        ist_prim=false;
                                        break;
                                }
                                if((*akt_prim_adresse)*(*akt_prim_adresse)>(*akt_zahl_adresse))break;//sollte akt_prim größer als die wurzel der akt_zahl sein, beende den spass (da sqrt langsam is hab ichs so umgeschrieben)
                        }
                if(ist_prim==true)//prim speichern
                {
                        prim_liste[akt_anzahl]=(*akt_zahl_adresse);
                        akt_anzahl++;
                }
                (*akt_zahl_adresse)+=2;
        }while(akt_anzahl<ges_anzahl);
        //filtern
        QueryPerformanceCounter( (LARGE_INTEGER*) &end_zeit);    //endzeit ermitteln

        cout << "\n";
        //for(unsigned int i=0;i<ges_anzahl;i++){cout << prim_liste[i] << "\n";}//ausgeben
        cout << "\nGefilterte Primzahlen: " << ges_anzahl << "\n";
        cout << "Zeit: " << (end_zeit - start_zeit) * TimeScale << " s\n\n";

        free(prim_liste);
        system("Pause");

        return 0;
}
//---------------------------------------------------------------------------



wo kann ich da noch was drehen?
wäre es zB sinnvoll meint wegen 100000 Primzahlen erst mal in nen statischen array zu speichern und erst wenn der voll is den dyn array erweitern und den ganzen Spass da rein schreiben?

MFG Starsurfer
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
18.12.2006, 11:34 Uhr
~Starsurfer
Gast


so hab wieder ein paar ms raus geholt...

500000 Primzahlen -> ~2.6 sec
1000000 Primzahlen -> ~7.5 sec
10000000 Primzahlen -> ~240 sec

aktuell is der code so:

C++:
//---------------------------------------------------------------------------

#include <iostream>
#include <windows>
#include <cmath>
using namespace std;
//---------------------------------------------------------------------------

int main()
{
        unsigned int akt_anzahl,ges_anzahl,akt_zahl;
        unsigned int *prim_liste; //dyn array für primzahlen
        unsigned int *akt_prim_adresse;  //zeiger auf element von prim array
        unsigned int *akt_zahl_adresse;  //zeiger auf akt_zahl
        unsigned int *array_start_adresse;
        unsigned int *array_end_adresse;
        unsigned int *array_akt_adresse;
        bool ist_prim;
        LONGLONG frequenz, end_zeit, start_zeit;
        double TimeScale;

        cin >> ges_anzahl;

        if((prim_liste=(unsigned int *) malloc(sizeof(unsigned int)*ges_anzahl))==NULL)//dyn array erzeugen
        {
                cout << "Nicht genug Speicher fuer Array\n\n";
                system("Pause");
                return 0;
        }
        prim_liste[0]=2;        //erste prim zahl setzen
        akt_anzahl=1;           //start parameter setzen
        akt_zahl=3;             //
        akt_zahl_adresse=&akt_zahl;
        array_start_adresse=&prim_liste[0];
        array_akt_adresse=&prim_liste[1];
        array_end_adresse=&prim_liste[ges_anzahl];

        QueryPerformanceFrequency((LARGE_INTEGER*) &frequenz);  //system freq ermitteln
        QueryPerformanceCounter((LARGE_INTEGER*) &start_zeit);     //anfangszeit ermitteln
        TimeScale = 1.0/frequenz;
        //filtern
        do
        {
                akt_prim_adresse=&prim_liste[0];
                ist_prim=true;
                for(unsigned int i=1;i<array_akt_adresse-array_start_adresse;i++)
                        {
                                akt_prim_adresse++;
                                if((*akt_zahl_adresse)%(*akt_prim_adresse)==0)
                                {
                                        ist_prim=false;
                                        break;
                                }
                                if((*akt_prim_adresse)*(*akt_prim_adresse)>(*akt_zahl_adresse))break;
                        }
                if(ist_prim==true)
                {
                        *array_akt_adresse=(*akt_zahl_adresse);
                        array_akt_adresse++;
                }
                (*akt_zahl_adresse)+=2;
        }while(array_akt_adresse<array_end_adresse);
        //filtern
        QueryPerformanceCounter( (LARGE_INTEGER*) &end_zeit);    //endzeit ermitteln

        cout << "\n";
        //for(unsigned int i=0;i<ges_anzahl;i++){cout << prim_liste[i] << "\n";}//ausgeben
        cout << "\nGefilterte Primzahlen: " << ges_anzahl << "\n";
        cout << "Zeit: " << (end_zeit - start_zeit) * TimeScale << " s\n\n";

        free(prim_liste);
        system("Pause");

        return 0;
}
//---------------------------------------------------------------------------


hat wer irgendwelche tipps
mal weiter suchen...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
06.01.2007, 16:19 Uhr
~Starsurfer
Gast


so wieder ein bisschen modifiziert:

500000 Primzahlen -> ~2.6 sec
1000000 Primzahlen -> ~6.8 sec
10000000 Primzahlen -> ~238 sec


C++:
//---------------------------------------------------------------------------

#include <iostream>
#include <windows>
#include <cmath>
using namespace std;
//---------------------------------------------------------------------------

int main()
{
        unsigned int ges_anzahl,akt_zahl,stempel_loop;
        unsigned int *prim_liste,           //dyn array für primzahlen
                     *akt_prim_adresse,     //zeiger auf element von prim array
                     *akt_zahl_adresse,     //zeiger auf akt_zahl
                     *array_start_adresse,
                     *array_end_adresse,
                     *array_akt_adresse,
                     *akt_stempel_adresse;
        bool ist_prim;
        LONGLONG frequenz, end_zeit, start_zeit;
        double TimeScale;
        unsigned int stempel[8]={1,7,11,13,17,19,23,29};  //Netz des Ulam

        cin >> ges_anzahl;
        // dyn array mittels new erzeugen ist nicht schneller
        if((prim_liste=(unsigned int *) malloc(sizeof(unsigned int)*ges_anzahl))==NULL)//dyn array erzeugen
        {
                cout << "Nicht genug Speicher fuer Array\n\n";
                system("Pause");
                return 0;
        }
        prim_liste[0]=2;        //erste 3 primzahlen setzen
        prim_liste[1]=3;        //
        prim_liste[2]=5;        //
        akt_zahl=3;             //start parameter setzen
        stempel_loop=0;         //
        akt_stempel_adresse=&stempel[1];              //pointer addressen übergeben
        akt_zahl_adresse=&akt_zahl;                   //
        array_start_adresse=&prim_liste[0];           //
        array_akt_adresse=&prim_liste[3];             //
        array_end_adresse=&prim_liste[ges_anzahl];    //

        QueryPerformanceFrequency((LARGE_INTEGER*) &frequenz); //system freq ermitteln
        QueryPerformanceCounter((LARGE_INTEGER*) &start_zeit); //anfangszeit ermitteln
        TimeScale = 1.0/frequenz;
        //filtern
        do
        {
                akt_prim_adresse=prim_liste;
                ist_prim=true;
                for(int i=1;i<array_akt_adresse-array_start_adresse;i++)
                        {
                                akt_prim_adresse++;
                                if((*akt_zahl_adresse)%(*akt_prim_adresse)==0)
                                {
                                        ist_prim=false;
                                        break;
                                }
                                if((*akt_prim_adresse)*(*akt_prim_adresse)>(*akt_zahl_adresse))break;
                        }
                if(ist_prim==true)
                {
                        *array_akt_adresse=(*akt_zahl_adresse);
                        array_akt_adresse++;
                }
                (*akt_zahl_adresse)=(*akt_stempel_adresse)+30*stempel_loop; //
                akt_stempel_adresse++;                                      //
                if(akt_stempel_adresse>&stempel[7])                         // Netz des Ulam
                {                                                           //
                        akt_stempel_adresse=stempel;                        //
                        stempel_loop++;                                     //
                }
        }while(array_akt_adresse<array_end_adresse);
        //filtern
        QueryPerformanceCounter( (LARGE_INTEGER*) &end_zeit);    //endzeit ermitteln

        cout << "\n";
        //for(unsigned int i=0;i<ges_anzahl;i++){cout << prim_liste[i] << "\n";}//ausgeben
        cout << "\nGefilterte Primzahlen: " << ges_anzahl << "\n";
        cout << "Zeit: " << (end_zeit - start_zeit) * TimeScale << " s\n\n";

        free(prim_liste);
        system("Pause");

        return 0;
}
//---------------------------------------------------------------------------



mmmh mir hat zwar noch keiner geantwortet aber vll hab ich ja Glück:

Gibts ne alternative zu modulo? ich brauch ja nich den genauen Rest wissen, ich brauch ja nur wissen obs teilbar is oder net...

Starsurfer
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
06.01.2007, 17:45 Uhr
Suba Esel



Bin auch noch sehr neu in C++, allerdings sind mir ein paar Sachen ein / aufgefallen:
- #include <windows> funkioniert bei mir nicht, es geht nur #include <windows.h>
- wenn dir die Zeit in Sekunden ausreicht, kannst du vor und nach dem Durchlauf durch time(0) die Zeit in Sekunden seid irgendeinem Tag im Jahr ~1980 abfragen und dann durch Subtraktion die verstrichene Zeit herausbekommen, vielleicht geht das etwas schneller
- vielleicht bringt es etwas Zeit, using namespace std; rauszunehmen, weil dann das Programm bei einigen Befehlen nicht nachsehen muss, welcher namespace gerade benutzt wird
- wenn du die Variante mit time(0) nimmst, kannst du denk ich mal auch windows(.h) rausschmeißen, könnte auch noch etwas Zeit bringen
--
Simon

Dieser Post wurde am 06.01.2007 um 17:46 Uhr von Suba Esel editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
06.01.2007, 19:02 Uhr
Suba Esel



Ich hab einfach mal eine eigene Funktion programmiert, die sehr viel einfacher, aber auch sehr viel langsamer ist:


C++:
#include <iostream>
#include <cmath>
//#include <fstream> // falls man das Ergebnis speichern will
using namespace std;

bool isprime(int n)
{
    if (n < 2 || n % 2 == 0 && n != 2) return false;
    if (n == 2) return true;

    for (int i = 3; i <= sqrt(n); i += 2)
    {
        if(n % i == 0)
        {
            return false;
        }
    }
    return true;
}

int main()
{
    unsigned long long int anzahl;
    cout << "Wieviele Primzahlen sollen angezeigt werden?" << endl;
    cin >> anzahl;
    cout << endl;
    cin.sync();
    //ofstream out("Primzahlen.txt"); // falls man das Ergebnis speichern will
    //out << anzahl << " Primzahlen \n\n"; // falls man das Ergebnis speichern will
    int j = 1;
    int startzeit = time(0);
    for (int i = 1;j <= anzahl;++i)
    {
        if (isprime(i))
        {
            //cout << j << ": " << i << endl; // falls man das Ergebnis anzeigen will
            //out << j << ": " << i << endl; // falls man das Ergebnis speichern will
            ++j;
        }
    }
    int endzeit = time(0);
    int gesamtzeit = endzeit - startzeit;
    cout << "Dauer: " << gesamtzeit << " Sekunden.";
    //out << "Dauer: " << gesamtzeit << " Sekunden."; // falls man das Ergebnis speichern will
    //out.close(); // falls man das Ergebnis speichern will
    cin.get();
}



Das Programm braucht auf meinem AMD Athlon 3500+ (2,2 GHz):
~37 Sekunden, wenn ich es so lasse (ist dann aber sinnlos )
~ 40 Sekunden, wenn ich in die Datei schreibe
~ 60 Sekunden, wenn ich die Zahlen ausgebe
~ 67 Sekunden, wenn ich in die Datei speichere und die Zahlen ausgebe
--
Simon

Dieser Post wurde am 06.01.2007 um 19:03 Uhr von Suba Esel editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
06.01.2007, 20:35 Uhr
Uwe
C/C++ Master
(Administrator)


Hallo,
*LOL* (ich meine die letzten beiden Postings)
Etwas schneller geht es damit

C++:
int _tmain(int argc, _TCHAR* argv[])
{
     iLONGLONG frequenz, end_zeit, start_zeit;
     double TimeScale;
     const unsigned int ges_anzahl = 10000000;
     unsigned int *Prim;
     if((Prim=(unsigned int *) malloc(sizeof(unsigned int)*ges_anzahl))==NULL)
        {
                cout << "Nicht genug Speicher fuer Array\n\n";
                return -1;
        }
     for ( int i = 0;i < ges_anzahl ;++i)
        Prim[i] = 1;
      
     unsigned int currentPrim = 2;
     unsigned int vielfaches;
    QueryPerformanceFrequency((LARGE_INTEGER*) &frequenz);  
    QueryPerformanceCounter((LARGE_INTEGER*) &start_zeit);  
    TimeScale = 1.0/frequenz;  
    while (currentPrim < (ges_anzahl + 1) / 2)
    {
    vielfaches = 2 * currentPrim ;
    if( Prim[currentPrim]){
        for(int i = 2;i <= ges_anzahl;++i){
            Prim[vielfaches] = 0;
            vielfaches += currentPrim;
            if( vielfaches > (ges_anzahl + 1))
                break;
        }
    }
    currentPrim += 1;
    }
   QueryPerformanceCounter( (LARGE_INTEGER*) &end_zeit);
    cout << "\n";
    cout << "Zeit: " << (end_zeit - start_zeit) * TimeScale << " s\n\n";
    // ggf Ausgabe
    /*for (int i = 2; i<= ges_anzahl ; ++i){
                if (Prim[i])
        cout << i << endl;
       }*/

return 0;
}


--
"Es ist schwierig, ein Programm wirklich idiotensicher zu machen, weil Idioten so genial sind."

Bis dann...
Uwe

Dieser Post wurde am 06.01.2007 um 20:51 Uhr von Uwe editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
07.01.2007, 11:17 Uhr
Suba Esel



@ Uwe:
Zitat:
*LOL* (ich meine die letzten beiden Postings)

Herzlichen Dank
Ich hab doch gesagt, dass ich noch Anfänger bin
Und ich wollte erstmal ein einfaches Programm schreiben, nicht ein schnelles
oder hab ich da jetzt was falsch verstanden?
--
Simon
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
07.01.2007, 12:51 Uhr
Suba Esel



Ach ja, ich glaube, es wäre noch einfacher, erst die ersten paar Milliarden Primzahlen in eine Datei zu speichern und dann einfach auszulesen, dass dauert einmal ganz lange und danach nur noch kurz

@ Uwe: die Header fehlen, und zumindest mein Compiler führt das Programm nicht aus, weil er _tmain() nicht kennt...
--
Simon

Dieser Post wurde am 07.01.2007 um 12:52 Uhr von Suba Esel editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
07.01.2007, 12:52 Uhr
Uwe
C/C++ Master
(Administrator)


Hallo,

Zitat von Suba Esel:
Ich hab doch gesagt, dass ich noch Anfänger bin
Und ich wollte erstmal ein einfaches Programm schreiben, nicht ein schnelles...

Hat doch jeder mal angefangen...
Aber den Post 003 streichen wir mal...
--
"Es ist schwierig, ein Programm wirklich idiotensicher zu machen, weil Idioten so genial sind."

Bis dann...
Uwe
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
07.01.2007, 12:54 Uhr
Suba Esel



Welchen Post 003 meinst du jetzt?

Den, den du zitiert hast?
--
Simon

Dieser Post wurde am 07.01.2007 um 12:55 Uhr von Suba Esel editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ] [ 3 ]     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: