我正在尝试在 c 中实现 PCG 随机数生成器。因为我是 c 的初学者,所以我很难理解这些例子。到目前为止,我尝试实现可以找到的最小版本 here .
这是我的代码,现在可以生成一些(希望如此)伪随机数:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include "pcg_basic.h"
int main(int argc, char** argv){
pcg32_random_t rngptr;
pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr);
for (int round = 1; round <= 10; ++round) {
printf(" %f\n", ldexp(pcg32_random_r(&rngptr) ,-32));
}
return 0;
}
这甚至是一个好的实现还是可以更好地改进?
问题:我想在我的代码中到处使用随机数,而不仅仅是在 main()
函数中。我怎样才能做到这一点?我试过:
double myrand(){
pcg32_random_t rngptr;
pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr);
return ldexp(pcg32_random_r(&rngptr) ,-32);
}
但是,这种方法行不通,对我来说似乎是错误的。但我不知道如何做得更好。
谁能告诉我一个简单的方法来在 c 语言中获得良好的伪随机数,该方法适用于代码的每个部分?
最佳答案
在不知道您使用的实现的情况下,查看这些行:
double myrand(){
pcg32_random_t rngptr;
pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr);
return ldexp(pcg32_random_r(&rngptr) ,-32);
}
第二行种子随机数生成器。在每次调用时都这样做会使实际的 PRNG 无效。
每个 PRNG 的工作原理都是保存一些内部状态,并使用一些或多或少复杂的算术运算从前一个状态计算下一个状态。然后将部分内部状态作为下一个“随机”数返回。
由于内部状态必须从某处开始,所以您必须播种每个 PRNG 恰好一次(并使用类似time ()
对于它,每次运行都从不同的地方开始。
此代码的一个简单版本可能如下所示:
double myrand(){
static int initialized = 0;
static pcg32_random_t rngptr;
if (!initialized)
{
pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr);
initialized = 1;
}
return ldexp(pcg32_random_r(&rngptr) ,-32);
}
这不再是线程安全的,因为整个程序中只有一个 PRNG 实例(由 pcg32_random_t
变量表示)。
另一种方法是使您的函数实际上采用指向您的 PRNG 的指针并在外部某处管理创建和播种(例如,一次在 main()
中):
double myrand(pcg32_random_t *rngptr){
return ldexp(pcg32_random_r(rngptr) ,-32);
}
int main(void)
{
// do this once:
pcg32_random_t rngptr;
pcg32_srandom_r(&rngptr, time(NULL), (intptr_t)&rngptr);
// [...]
double x = myrand(&rngptr);
}
基本相同的事情适用于 C 标准函数 srand()
和 rand()
:您必须恰好调用一次 srand()
用于播种 PRNG。使用这些函数,内部状态是static
(在 C 标准库中),因此您不必传递任何内容,并且使用这些函数不是线程安全的。
这是一个非常简单和愚蠢的标准 C rand()
示例实现,用于 0x7fffffff
的 RAND_MAX
>,这可能有助于更好地理解 PRNG 的一般概念:
static unsigned long long int randval = 1;
void srand(unsigned int seed)
{
randval = seed;
}
int rand(void)
{
randval *= 1103515245;
randval += 12345;
return (int)((randval / 65536) & 0x7fffffff);
}
如您所见,randval
是保密的,但调用 srand()
会设置它,因此会影响下一次调用 rand() 的结果
。
关于c:使用 PCG 实现生成随机数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47137488/