5

我不确定为什么这两个代码块会给出不同的输出:

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

对比

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

我误解了什么 setstate() 吗?

编辑:有趣的是,看看这给出了什么:

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
4

4 回答 4

3

两种实现都是正确的。

Setstate 只是将例程中的静态指针更改为指向您的缓冲区。

允许 Initstate 做同样的事情,但也允许先更改缓冲区内容。如果 PRNG 类似于 ARC4 或 Spritz,则缓冲区需要是一个排列,而不仅仅是任意位。如果 PRNG 是非线性加性反馈生成器,则至少需要设置状态中某处的低位之一,否则它将无法正常工作。并且一些库对状态缓冲区进行哈希处理,因此仅从种子+输出信息中就不容易判断正在使用哪种 PRNG。他们不需要;如果它使用的生成器是 LFSG 或不需要任何特定格式或对缓冲区有任何一致性需求的东西,则 lib 可以对 initstate 和 setstate 执行完全相同的操作。但是如果你不做 initstate,而你的操作系统使用了有这种需求的东西,

于 2016-08-11T20:41:10.610 回答
2

我猜对的调用initstate()也不会切换到该状态,但对的调用setstate()确实如此,这就是为什么后一个random()调用返回从新状态生成的数字的原因。

于 2012-12-06T10:18:12.607 回答
2

BSD 实现在setstate将辅助状态信息存储到旧缓冲区之前加载辅助状态信息,以进行错误检查。此外initstatesetstate是更新此信息的唯一功能。这意味着当使用相同的缓冲区时,它会加载陈旧状态存储新数据,并使用前者更新内部状态。以这种方式重复调用setstate将交替旧存储状态和当前内部状态,导致调用两次时观察到的结果。

的评论setstate说用当前缓冲区调用它是可以的,所以要么这是预期的行为,要么是几十年前的错误。

请注意,由于事情的完成顺序,可以调用 setstate() 与当前状态相同的状态。

于 2016-08-11T22:50:16.560 回答
1

initstate()告诉 random 使用什么缓冲区来存储下一个随机数的信息。random()由于缓冲区中的信息state1[256]已更改,您在调用中会得到不同的答案。查看以下代码的输出:

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

这给出了输出:

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

可以看到第一次调用后random()缓冲区的内容发生了state1变化。random()使用该区域来存储其状态。此状态被复制到缓冲区tmp。稍后我们将其复制回state1,并获得相同的随机数序列。请注意,在您复制到应该用于随机数的缓冲区或从缓冲区复制之前,您必须使用or告诉random()停止使用该缓冲区。原因是当被调用时,旧缓冲区被修改以允许它再次被加载。setstate()initstate()setstate()setstate()

因此,要获得与原始问题相同的答案,您必须使用:

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());
于 2017-09-12T19:25:48.917 回答