Zufaellige zeile auslesen.



  • Hi,
    ich hoffe jemand kann mir sagen wie ich zufaellig eine einzige Zeile aus einem Textdokument ausgeben kann.

    Bis Jetzt:

    #include <cstdlib>
    #include <iostream>
    #include <string>
    #include <stdio.h>
    
    using namespace std;
    
    char datnam[40] = "Sprueche.txt";
    
    int main( void )
    {
            FILE * datei;   
            char zeile[80]; 
    
            datei = fopen( datnam, "r" );
            if( datei == 0 )
            {
                    printf("Fehler: Datei existiert nicht");
                    return 1;
            }
            fgets( zeile, 2, datei );
            while( ! feof(datei) )
            {
                    printf("%s", zeile );
                    fgets( zeile, 2, datei );
            }
            fclose( datei );
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Wo und wie bastel ich jetzt das so ein, das er jedes mal nur eine zufaellig Zeile ausgibt?

    Aber bitte richtige Zufallszeilen und nicht

    string chars("123456789");
        int length=rand()%1+2;
        string res("");
        for(int i=0;i<length;++i)
            res=res+chars[rand()%chars.length()];
        return res;
    

    MfG
    Coda



  • Zeilen haben keine feste Länge, also müsstest du eine Liste anlegen, bei welchem Index jede Zeile beginnt - dann würfelst du zufällig ein Element aus dieser Liste aus, springst mit seekp() an die dort gespeicherte Position und setzt an zu Lesen.

    (PS: Und tu dir den Gefallen und steig auf fstream's um)



  • Neue Idee....

    Wie waehre es wenn ich einfach jede Zeile einem array zuweise und dann aus dem array dann ne zufaellige Zahl bestimme, welche dann ausgegeben wird (die Zeile aus dem zufaelligen array)

    Bitte mal ne Stellung zu der Idee, ob das ueberhaupt geht.

    Danke

    MfG
    Coda



  • Hallo

    Das hört sich doch ganz nach der Idee von CStoll an: Alle Zeilen einlesen (in array, vector oder list) und dann eine zufällig auswählen.

    chrische



  • nur einmal lesen ist hier vermutlich netter.

    srand(time(0));//nur einmal am anfang der main()
    
    ifstream in("Sprueche.txt");
    line result;
    int count=1;
    while(getline(in,line)){
       if(rand()%count==0){
          result=line;
          ++count;
       }
    }
    cout<<result<<'\n';
    


  • Hallo !

    Für die Berechnung der Zufallszahl musst du die Anzahl deiner Zeilen
    kennen, nennen wir die Anzahl deiner Zeilen mal n.

    Deine erste Zeile soll mit der Zahl 0, deine letzte Zeile mit der Zahl
    n-1 erreichbar sein:

    0 <= index <= n-1

    Die Zahl index soll auch die gesuchte Zufallszahl sein.

    Ob du die Zeile dann direkt von der Festplatte liest, oder aus einem
    Array im Arbeitsspeicher, ist für die Berechung der Zufallszahl uninteressant.

    Die Funktion rand() liefert dir eine Zufallszahl, nennen wir sie mal R.

    R liegt in einem Bereich von 0 bis RAND_MAX.
    RAND_MAX ist in der stdlib.h definiert und abhängig vom Compiler:

    #define RAND_MAX 2147483647 // DJGPP ( gcc )
    #define RAND_MAX 0x777F // Visual Studio
    #define RAND_MAX ???? // Weiss der Geier was fürn Compiler

    Du hast also zwei Wertebereiche:

    0<= R <= RAND_MAX // Wertebereich der rand() Funktion
    0<= index <= n-1 // Dein Wertebereich

    Durch Verhältnisbildung kannst du jetzt deinen Wertebereich auf
    dem Wertebereich der rand() Funktion abbilden und erhälst eine
    Verhältnisgleichung:

    index / n-1 = R / RAND_MAX

    Aufgelöst nach der gesuchten Zufallszahl:

    index = R * (n-1) / RAND_MAX

    Durch diese Verhältnisbildung bekommst du immer einen index geliefert,
    der mindestens 0 und maximal n-1 ist.

    Das lässt sich leicht überprüfen:
    Setze R = 0, dann wird index = 0;
    Setze R = RAND_MAX, dann wird index = n-1

    Da ja R von rand() geliefert wird ergibt das eingesetzt:

    index = rand() * ( n-1 ) / RAND_MAX

    Der dafür erforderliche Quellcode ist zum Glück erheblich knapper als die obige Erklärung:

    #include <time.h>
    #include <stdlib.h>
    
    void main()
    {
       unsigned long index = 2, n=0; // Setze n = Anzahl_deiner_Zeilen
       srand( (unsigned)time( NULL ) );
       index =  rand() * ( n - 1 )  / RAND_MAX; // index ist die gesuchte Zufallszahl
    }
    

    Frohe Ostern und Gruß,
    p.



  • warum index = rand() * ( n - 1 ) / RAND_MAX; statt index=rand()%n ? die formel ist eigenlich nicht mehr in, denn sie behebt kein problem, aber schafft ein paar neue. du hast recht früh überlauffehler beim GCC. sehr fruh, wie mir scheint.

    "Für die Berechnung der Zufallszahl musst du die Anzahl deiner Zeilen
    kennen, nennen wir die Anzahl deiner Zeilen mal n." ist nicht so ganz richtig, wie ich im posting zuvor bewies.



  • volkard schrieb:

    nur einmal lesen ist hier vermutlich netter.

    srand(time(0));//nur einmal am anfang der main()
    
    ifstream in("Sprueche.txt");
    line result;
    int count=1;
    while(getline(in,line)){
       if(rand()%count==0){
          result=line;
          ++count;
       }
    }
    cout<<result<<'\n';
    

    so weit so gut aber wie kann ich result vom typ line haben??? An der Stelle steig ich nicht so dahinter, mein Compiler auch nicht.

    MfG
    Coda



  • volkard schrieb:

    warum index = rand() * ( n - 1 ) / RAND_MAX; statt index=rand()%n ? die formel ist eigenlich nicht mehr in

    Wo kann man denn etwas über das "in sein" dieser Formel erfahren ?

    volkard schrieb:

    du hast recht früh überlauffehler beim GCC. sehr fruh, wie mir scheint.

    Es gibt keinen Überlauf beim unsigned Datentypen, es wird mit der Modulo-Arithmetik weiter gerechnet.

    volkard schrieb:

    "Für die Berechnung der Zufallszahl musst du die Anzahl deiner Zeilen
    kennen, nennen wir die Anzahl deiner Zeilen mal n." ist nicht so ganz richtig, wie ich im posting zuvor bewies.

    Natürlich musst du die Anzahl kennen, du berechnest die Anzahl in deiner Schleife immer wieder neu. Darüber hinaus wird rand() pro eingelesene Zeile aufgerufen, in meiner Version nur einmal 😃



  • Coda@linux.PrayLoad schrieb:

    so weit so gut aber wie kann ich result vom typ line haben???

    sorry, string war gemeint.

    habs mal mit ohne ungetestet gemacht.

    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <ctime>
    #include <string>
    
    using namespace std;
    
    int main(){
    	srand(static_cast<int>(time(0)));rand();//nur einmal am anfang der main() 
    
    	ifstream in("C:/LogiSetup.log"); 
    	string result;
    	string line;
    	int count=1; 
    	while(getline(in,line)){ 
    	   if(rand()%count==0){ 
    		  result=line; 
    		  ++count; 
    	   } 
    	} 
    	cout<<result<<'\n'; 
    }
    


  • da hab ich bestimmt nen programmierfehler gemacht.
    ich wollte mal sehen, ob die beiden ergebnisse einigermaßen gleichwahrscheinlich sind.

    #include <iostream>
    using namespace std;
    
    int main(){
        unsigned int const n=2;
        int count[n]={0};
        for(int i=0;i<1000000;++i){
            int index = rand() * ( n - 1 ) / RAND_MAX;
    //        int index = rand() % n;
            ++count[index];
        }
        for(int i=0;i<n;++i){
            cout<<i<<' '<<count[i]<<'\n';
        }
    }
    

    ausgabe:

    0 999963
    1 37
    

    was stimmt da nicht?


  • Mod

    wenn überhaupt, dann wohl

    rand()*n/(RAND_MAX+1)
    

    Das spart u.U. eine Division, was allerdings im Verhältnis zum Aufwand von rand eher unbedeutend sein dürfte. So lange n klein gegen RAND_MAX ist, wird es praktisch keine Rolle spielen, welche Formel man verwendet.

    Interessanter dürfte die Frage sein, wie viele Zeilen die Quelle haben darf, bevor volkards Methode starke Abweichungen von der Gleichverteilung zeigt, weil entsprechend kleine Wahrscheinlichkeiten nicht mehr hinreichend exakt dargestellt werden können (was man wiederum durch Verkettung von rand beheben könnte).



  • volkard schrieb:

    ich wollte mal sehen, ob die beiden ergebnisse einigermaßen gleichwahrscheinlich sind.

    Interessante Idee, der Sache werd ich nachgehen, aber heute wird das wohl nix mehr.
    Gruß,
    p.



  • camper schrieb:

    wenn überhaupt, dann wohl

    rand()*n/(RAND_MAX+1)
    

    Das spart u.U. eine Division, was allerdings im Verhältnis zum Aufwand von rand eher unbedeutend sein dürfte. So lange n klein gegen RAND_MAX ist, wird es praktisch keine Rolle spielen, welche Formel man verwendet.

    ich krieg das mit dieser formel auch nicht hin, wenn RAND_MAX==INT_MAX. hab mir sagen lassen, das sei jetzt auf modwernen compilern so.

    Interessanter dürfte die Frage sein, wie viele Zeilen die Quelle haben darf, bevor volkards Methode starke Abweichungen von der Gleichverteilung zeigt, weil entsprechend kleine Wahrscheinlichkeiten nicht mehr hinreichend exakt dargestellt werden können (was man wiederum durch Verkettung von rand beheben könnte).

    nur bis RAND_MAX zeilen.

    vorschlag zur behebung, solange MS kleines RAND_MAX hat.

    unsigned r2=0;
        while(getline(in,line)){ 
           r2=r2*3+rand();
           if((r2%count==0){
    


  • camper schrieb:

    Das spart u.U. eine Division

    Welche Divion willst du sparen ? Es gibt nur eine.


  • Mod

    volkard schrieb:

    camper schrieb:

    wenn überhaupt, dann wohl

    rand()*n/(RAND_MAX+1)
    

    Das spart u.U. eine Division, was allerdings im Verhältnis zum Aufwand von rand eher unbedeutend sein dürfte. So lange n klein gegen RAND_MAX ist, wird es praktisch keine Rolle spielen, welche Formel man verwendet.

    ich krieg das mit dieser formel auch nicht hin, wenn RAND_MAX==INT_MAX. hab mir sagen lassen, das sei jetzt auf modwernen compilern so.

    Um dieses triviale Problem geht es mir nicht. Dass man dafür sorgen muss, dass rand()*n keine Überläufe produziert, ist sowieso klar (wobei wir hier möglicherweise sogar mit Überläufen leben können, da RAND_MAX ja meist irgendein 2^n-1 ist). Ein hinreichend großer Datentyp muss es schon sein. Gleiches gilt entsprechend für RAND_MAX+1.

    rand()*(n-1)/RAND_MAX
    

    ist dagegen offensichtlich schlechter als rand()%n
    Denn die wahrscheinlichkeit, dass hierbei n-1 (für n>1) herauskommt, ist immmer nur 1/RAND_MAX

    volkard schrieb:

    Interessanter dürfte die Frage sein, wie viele Zeilen die Quelle haben darf, bevor volkards Methode starke Abweichungen von der Gleichverteilung zeigt, weil entsprechend kleine Wahrscheinlichkeiten nicht mehr hinreichend exakt dargestellt werden können (was man wiederum durch Verkettung von rand beheben könnte).

    nur bis RAND_MAX zeilen.

    Das ist klar; mir geht es um den Fehler, der sich schon vorher mit jedem Durchgang fortpflanzt.

    volkard schrieb:

    vorschlag zur behebung, solange MS kleines RAND_MAX hat.

    unsigned r2=0;
        while(getline(in,line)){ 
           r2=r2*3+rand();
           if((r2%count==0){
    

    Das ergibt immer noch nicht mehr Möglichkeiten in jedem Durchgang. Wie wäre es mit

    if((rand()+rand()*(RAND_MAX+1)%n==0){
    

  • Mod

    proggingmania schrieb:

    camper schrieb:

    Das spart u.U. eine Division

    Welche Divion willst du sparen ? Es gibt nur eine.

    Eine Division durch eine Potenz von 2 die üblicherweise durch schnelles Bitverschieben implementiert wird. Wie schon gesagt, das ist ein unbedeutender Fakt.



  • Neee neee

    rand()*(n-1)/ RAND_MAX // eine Division
    rand()*n/(RAND_MAX+1) // auch eine Division

    Gesparte Anzahl Divisionen == 0
    😉

    Dieser Service bietet "echte" Zufallszahlen die durch weißes atmospärischen Rauschen entstehen:
    http://www.random.org/
    Nehmen wir diese Zahlen, können wir uns eine Diskussion sparen
    *g*

    LG,
    p.



  • camper schrieb:

    Das ist klar; mir geht es um den Fehler, der sich schon vorher mit jedem Durchgang fortpflanzt.

    welchen fehler genau?

    ich sehe keinen bei

    string result; 
        string line; 
        int count=1; 
        while(getline(in,line)){ 
           if(rand()%count==0){ 
              result=line; 
              ++count; 
           } 
        } 
        cout<<result<<'\n';
    

    außer, daß RAND_MAX kleiner sein könnte als die zeilenzahl.

    was pflanzt sich da durch?



  • camper schrieb:

    Denn die wahrscheinlichkeit, dass hierbei n-1 (für n>1) herauskommt, ist immmer nur 1/RAND_MAX

    Na, mal gut das das so ist, wenn man eine Gleichverteilung möchte.


Anmelden zum Antworten