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 CompilerDu hast also zwei Wertebereiche:
0<= R <= RAND_MAX // Wertebereich der rand() Funktion
0<= index <= n-1 // Dein WertebereichDurch 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-1Da 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 37was stimmt da nicht?
-
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.
-
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_MAXist dagegen offensichtlich schlechter als rand()%n
Denn die wahrscheinlichkeit, dass hierbei n-1 (für n>1) herauskommt, ist immmer nur 1/RAND_MAXvolkard 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){
-
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 DivisionGesparte 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.