Die Antwort von Mark ist fast richtig, bis auf zwei Punkte:
- Wenn eine Zeile länger ist als
length - 1
Zeichen (einschließlich des Zeilenumbruchs), dann wird die while
Schleife wird inkrementiert count
mindestens zweimal für dieselbe Zeile: einmal für die erste length - 1
Zeichen, ein weiteres für das nächste length - 1
Zeichen, etc.
- Die Berechnung der
rand() * count
kann einen Integer-Überlauf verursachen.
Um das erste Problem zu lösen, können Sie fgets
in einen Papierkorb, bis er zurückkehrt NULL
(was auf einen E/A-Fehler oder EOF ohne gelesene Daten hinweist) oder der Papierkorbpuffer enthält einen Zeilenumbruch:
count = 0;
while (fgets(line, length, stream) != NULL)
{
char *p = strchr(line, '\n');
if (p != NULL) {
assert(*p == '\n');
*p = '\0'; // trim the newline
}
else { // haven't reached EOL yet. Read & discard the rest of the line.
#define TRASH_LENGTH 1024
char trash[TRASH_LENGTH];
while((p = fgets(trash, TRASH_LENGTH, stream)) != NULL) {
if ((p = strchr(trash, '\n')) != NULL) // reached EOL
break;
}
}
assert(strchr(line, '\n') == NULL); // `line` does not contain a newline
count++;
// ...
Das zweite Problem kann mit dem Vorschlag von @tvanfosson gelöst werden, wenn keine Fließkommaarithmetik verfügbar ist:
int one_chance_in(size_t n)
{
if (rand() % n == 0) // `rand` returns an integer in [0, `RAND_MAX`]
return 1;
else
return 0;
}
Aber beachten Sie, dass rand() % n
ist keine einheitliche, diskrete Zufallsvariable auch wenn rand()
wird als eins angenommen, weil die Wahrscheinlichkeit, dass rand() % n == 0
kann so viel wie 1/ RAND_MAX
höher als die gewünschte Wahrscheinlichkeit 1/ n
. Auf meinem Rechner, RAND_MAX
ist 2147483647, also beträgt die Differenz 4,66 × 10 -10 , aber der C-Standard verlangt nur, dass RAND_MAX
mindestens 32767 betragen (3,05 × 10 -5 Unterschied).
Für alle, die sich (wie ich) fragen, warum dieses Schema funktioniert, könnte es hilfreich sein, die Berechnung der Wahrscheinlichkeit durchzugehen, dass die erste Zeile in keptline
wenn es m Linien und verallgemeinern: Bei der ersten Iteration der Schleife ist die Wahrscheinlichkeit, dass die erste Zeile nach keptline
ist 1/1. Bei der zweiten Iteration der Schleife ist die Wahrscheinlichkeit, dass die zweite Zeile nicht Überschreiben der ersten Zeile ist 1/2. Bei der dritten Iteration ist die Wahrscheinlichkeit, dass die dritte Zeile nicht die erste Zeile zu überschreiben, beträgt 2/3. Die Wahrscheinlichkeit, dass die letzte Zeile die erste Zeile nicht überschreibt, ist also ( m - 1)/ m . Somit bleibt die Wahrscheinlichkeit, dass die erste Zeile in keptline
nach Iteration über alle Zeilen ist:
1/1 × 1/2 × 2/3 × 3/4 × ... × ( m - 2)/( m - 1) × ( m - 1)/ m \= 1/ m
Die Wahrscheinlichkeit, dass die zweite Zeile bleibt in keptline
ist:
1/2 × 2/3 × 3/4 × ... × ( m - 2)/( m - 1) × ( m - 1)/ m \= 1/ m
Die Wahrscheinlichkeit, dass die dritte Zeile bleibt in keptline
ist:
1/3 × 3/4 × ... × ( m - 2)/( m - 1) × ( m - 1)/ m \= 1/ m
Etc. Sie sind alle 1/ m .