2012-12-06 22 views
5

jestem pewien, dlaczego te dwa bloki kodu dają różne wyjścia:C funkcja random() setstate nie zachowuje się zgodnie z oczekiwaniami

unsigned int seed1 = 0; 
char state1[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
printf("%10ld\n", random()); 
// Gives: 
// 1216130483 
// 1950449197 

porównaniu

unsigned int seed1 = 0; 
char state1[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
setstate(state1); 
printf("%10ld\n", random()); 
// Gives: 
// 1216130483 
// 625602885 

jestem nieporozumienie co setstate() robi?

EDIT: Co ciekawe, patrzeć na to co to daje:

unsigned int seed1 = 0; 
char state1[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
setstate(state1); 
setstate(state1); 
printf("%10ld\n", random()); 
// Gives: 
// 1216130483 
// 1950449197 
+1

C ma tylko 'rand' i' srand' i ani 'random',' lub 'setstate' initstate' . Oznacz swoje pytanie swoim systemem operacyjnym. –

+1

@JensGustedt Dodałem tag bsd. – unwind

+0

Uruchamianie tego przykładu na Debianie (stabilnym) przy użyciu 'gcc (Debian 4.4.5-8) 4.4.5' Otrzymuję te same dwie liczby dla wszystkich trzech fragmentów kodu. – alk

Odpowiedz

2

Chyba wywołanie initstate() nie przełączyć się do tego stanu, ale wezwanie do setstate() nie, dlatego ten ostatni random() call zwraca numer wygenerowany z nowego stanu.

+2

Po eksperymentowaniu z kodem, wydaje mi się, że tak nie jest. Dodanie wywołania 'setstate()' zaraz po 'initstate() 'nie robi żadnej różnicy. – NPE

3

Obie implementacje są poprawne.

Setstate po prostu zmienia wskaźnik statyczny w podprogramie tak, aby wskazywał na bufor.

Initstate może zrobić to samo, ale może także najpierw zmienić zawartość bufora. Jeśli PRNG jest podobny do ARC4 lub Spritz, bufor musi być permutacją, a nie tylko arbitralnym bitem. Jeśli PRNG jest nieliniowym generatorem sprzężeń dodatków, to przynajmniej jeden z niskich bitów w jakimś stanie musi być ustawiony lub nie będzie działał poprawnie. I niektóre biblioteki mieszają bufor stanu, więc nie będzie łatwo stwierdzić, jaki rodzaj PRNG jest używany tylko z informacji o źródle + dane wyjściowe. Nie są wymagane; lib może zrobić dokładnie to samo dla initstate i setstate, jeśli generator, którego używa, to LFSG lub coś, co nie wymaga żadnego konkretnego formatu lub nie ma żadnych potrzeb w zakresie spójności dla bufora. Ale jeśli nie zrobisz initstate, a twój system operacyjny użyje czegoś, co ma takie potrzeby, twoja powtarzalna sekwencja może nie być tak nieprzewidywalna, jak byś chciała.

2

Implementacja BSD setstate ładuje pomocnicze informacje o stanie, w celu sprawdzenia błędów, przed zapisaniem go w starym buforze. Ponadto initstate i setstate to jedyne funkcje, które aktualizują te informacje. Oznacza to, że gdy używany jest ten sam bufor, to jest on: loads stale state, stores the new data i updates the internal state with the former. W ten sposób kilkakrotne wywoływanie numeru setstate spowoduje zmianę stanu starego i bieżącego stanu wewnętrznego, co spowoduje zaobserwowanie wyników po dwukrotnym wywołaniu.

The comment for setstate mówi, że wywoływanie go z bieżącym buforem jest OK, więc albo to jest zamierzone zachowanie, albo błąd decades old.

Należy pamiętać, że ze względu na kolejność, w której rzeczy są zrobione, że jest OK, aby zadzwonić setState() z tym samym stanie jak obecnego stanu.

1

mówi losowo, jaki bufor użyć do przechowywania informacji o następnej losowej liczbie. Otrzymujesz różne odpowiedzi w rozmowach na numer random(), ponieważ informacje w twoim buforze state1[256] uległy zmianie.Spójrz na wyjściu następujący kod:

#define LEN (32) 
void print_hex(char *b) 
{ 
    int i; 
    for(i=0; i < LEN; i++) printf("%02x ",((unsigned char *)b)[i]);  
    printf("\n"); 
} 

main() 
{ 
    char state1[256], state2[256], tmp[256]; 
    initstate(42, state2, LEN); 
    initstate(62, state1, LEN) ; 
    printf("buffer before random():\n"); 
    print_hex(state1) ; 
    printf("%10ld\n", random()); 
    printf("buffer after random():\n"); 
    print_hex(state1) ; 

    setstate(state2); // Now we are free to copy data from state1 
    printf("buffer after setstate():\n"); 
    print_hex(state1) ; 
    memcpy(tmp, state1, 256); 
    printf("copied to tmp\n"); 

    setstate(state1); // Go on with original sequence 
    printf("next random():\n") ; 
    printf("%10ld\n", random()); 
    printf("next random():\n") ; 
    printf("%10ld\n", random()); 

    setstate(state2) ; // Again, this allows us to play with data in state1 
    memcpy(state1, tmp, 256); 
    setstate(state1) ; 
    printf("back copy:\n"); 
    printf("random() after copy:\n") ; 
    printf("%10ld\n", random()); 
    printf("next random():\n") ; 
    printf("%10ld\n", random()); 
} 

Daje wyjście:

buffer before random(): 
01 00 00 00 e7 22 1d 21 f1 62 9c 90 89 72 b5 89 35 2b 97 b5 76 8c ff a8 56 14 14 7b ba 19 d9 f7 
1801070350 
buffer after random(): 
01 00 00 00 e7 22 1d 21 f1 62 9c 90 89 72 b5 89 1c 4e b4 d6 76 8c ff a8 56 14 14 7b ba 19 d9 f7 
buffer after setstate(): 
06 00 00 00 e7 22 1d 21 f1 62 9c 90 89 72 b5 89 1c 4e b4 d6 76 8c ff a8 56 14 14 7b ba 19 d9 f7 
copied to tmp 
next random(): 
483260339 
next random(): 
    40158063 
back copy: 
random() after copy: 
483260339 
next random(): 
40158063 

Widać, że po pierwszym wywołaniu random() zawartość bufora state1 zmian. random() używa tego obszaru do przechowywania jego stanu. Ten stan jest kopiowany do bufora tmp. Później kopiujemy go z powrotem do state1 i otrzymujemy tę samą sekwencję liczb losowych. Należy pamiętać, że przed skopiowaniem do bufora lub z bufora, który ma być użyty do liczb losowych, należy powiedzieć random(), aby przestał używać tego bufora przy użyciu setstate() lub initstate(). Powodem jest to, że gdy wywoływany jest setstate(), stary bufor jest modyfikowany, aby umożliwić jego ponowne ładowanie za pomocą setstate().

Tak, aby uzyskać tę samą odpowiedź jak w oryginalnym pytanie, trzeba użyć:

unsigned int seed1 = 42; 
char state1[256], tmp[256]; 
initstate(seed1, state1, 256); 
printf("%10ld\n", random()); 
initstate(0, tmp, 256); // <- notice this 
setstate(state1) ; 
printf("%10ld\n", random()); 
Powiązane problemy