2012-12-06 36 views
5

Tôi không chắc chắn lý do tại sao hai khối các mã cho đầu ra khác nhau:C ngẫu nhiên() & setstate chức năng không hoạt động như mong

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

vs

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

Tôi có hiểu lầm gì setstate() làm?

EDIT: Điều thú vị đủ, nhìn vào những gì điều này mang lại:

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 chỉ có 'rand' và' srand' và không 'random', 'initstate' hoặc' setstate' . Vui lòng gắn thẻ câu hỏi của bạn với hệ điều hành của bạn. –

+1

@ JensGustedt Tôi đã thêm thẻ bsd. – unwind

+0

Chạy ví dụ này trên Debian (ổn định) bằng cách sử dụng 'gcc (Debian 4.4.5-8) 4.4.5' Tôi nhận được hai số giống nhau cho cả ba đoạn mã. – alk

Trả lời

2

Tôi đoán các cuộc gọi đến initstate() không cũng chuyển sang trạng thái đó, nhưng cuộc gọi đến setstate() không, đó là lý do thứ hai Gọi random() trả về một số được tạo từ trạng thái mới.

+2

Sau khi thử nghiệm mã một chút, tôi không nghĩ đây là trường hợp. Thêm một cuộc gọi đến 'setstate()' ngay sau khi 'initstate()' làm cho không có sự khác biệt nào. – NPE

3

Cả hai cách triển khai đều chính xác.

Setstate chỉ thay đổi con trỏ tĩnh trong thường trình để trỏ vào bộ đệm của bạn.

Initstate được phép thực hiện tương tự, nhưng cũng được phép thay đổi nội dung bộ đệm trước. Nếu PRNG giống như ARC4 hoặc Spritz, bộ đệm cần phải là một hoán vị hơn là các bit tùy ý. Nếu PRNG là một bộ tạo phản hồi phụ gia phi tuyến, thì ít nhất một trong các bit thấp ở đâu đó trong trạng thái cần được thiết lập hoặc nó sẽ không hoạt động đúng. Và một số libs băm bộ đệm trạng thái để nó sẽ không dễ dàng để nói loại PRNG nào được sử dụng chỉ từ thông tin đầu ra của hạt giống +. Họ không bắt buộc phải; lib có thể làm chính xác điều tương tự cho initstate và setstate nếu trình tạo nó sử dụng là LFSG hay cái gì đó không yêu cầu bất kỳ định dạng cụ thể nào hoặc có bất kỳ nhu cầu nhất quán nào cho bộ đệm. Nhưng nếu bạn không làm initstate, và hệ điều hành của bạn sử dụng một cái gì đó có nhu cầu như vậy, chuỗi lặp lại của bạn có thể không được như không thể đoán trước như bạn muốn.

2

Việc triển khai BSD setstate tải thông tin trạng thái phụ, vì mục đích kiểm tra lỗi, trước khi lưu trữ vào bộ đệm cũ. Ngoài ra initstatesetstate là các chức năng duy nhất cập nhật thông tin này. Điều này có nghĩa là khi cùng một bộ đệm được sử dụng nó loads stale state, stores the new dataupdates the internal state with the former. Gọi setstate theo cách này nhiều lần sẽ thay thế trạng thái được lưu trữ cũ và trạng thái nội bộ hiện tại, gây ra kết quả quan sát được khi được gọi hai lần.

The comment for setstate nói rằng việc gọi nó bằng bộ đệm hiện tại là OK, do đó, đây là hành vi dự định hoặc lỗi decades old.

Lưu ý rằng do thứ tự mà mọi thứ được thực hiện, bạn có thể gọi setstate() với cùng trạng thái như trạng thái hiện tại.

1

initstate() cho biết bộ đệm nào sử dụng để lưu trữ thông tin cho số ngẫu nhiên tiếp theo. Bạn nhận được các câu trả lời khác nhau trong các cuộc gọi tới random() vì thông tin trong bộ đệm của bạn state1[256] đã thay đổi.Nhìn vào kết quả của đoạn mã sau:

#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()); 
} 

này cho kết quả:

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 

Bạn có thể thấy rằng sau khi cuộc gọi đầu tiên random() các nội dung của bộ đệm state1 thay đổi. random() sử dụng khu vực đó để lưu trữ trạng thái của nó. Trạng thái này được sao chép vào bộ đệm tmp. Sau đó chúng tôi sao chép nó trở lại state1 và nhận được cùng một chuỗi các số ngẫu nhiên. Lưu ý rằng trước khi bạn sao chép vào hoặc từ bộ đệm được cho là được sử dụng cho các số ngẫu nhiên, bạn phải thông báo random() để ngừng sử dụng bộ đệm đó bằng cách sử dụng setstate() hoặc initstate(). Lý do là khi setstate() được gọi, bộ đệm cũ được sửa đổi để cho phép nó được tải lại với setstate().

Vì vậy, để có được câu trả lời tương tự như trong câu hỏi ban đầu, bạn phải sử dụng:

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()); 
Các vấn đề liên quan