获取大于 RAND_MAX 的随机数

zzz*_*991 5 c++

Andrew Koenig的Accelerated C++问题 7-9 提问:

7-9。(困难)第 7.4.4/135 节中的 nrand 实现不适用于大于 RAND_MAX 的参数。通常,这个限制没有问题,因为无论如何 RAND_MAX 通常是最大可能的整数。尽管如此,在某些实现中 RAND_MAX 远小于最大可能的整数。例如,RAND_MAX 为 32767 (2^15 -1) 并且最大可能的整数为 2147483647 (2^31 -1) 的情况并不少见。重新实现 nrand,使其适用于所有 n 值。

如果n > RAN_MAX我的想法要采取

double temp = n/RAN_MAX + .5;
int mult = temp;
int randomNum = 0;

for (int i = 0; i != mult; mult++)
    randomNum += rand();
Run Code Online (Sandbox Code Playgroud)

然后测试是否randomNum < n。这可以生成随机数> RAND_MAX吗?我不知道如何使用比我的计算机可以处理的更大的整数,所以我认为没有任何真正的方法可以分辨。

Ric*_*ard 4

如果你真的在处理大于你的计算机可以处理的整数,那就很复杂了。

但是对于大于 的整数,您确实有多种选择int,其中包括:unsigned intlongunsigned longlong longunsigned long long按大小递增的顺序。具体数字有多大取决于您的架构。

例如,在我的机器上有以下内容:

Data Type:   Bytes  Minimum               Maximum
Short SInt:  2      -32768                32767
Short UInt:  2      0                     65535
UInt:        4      0                     4294967295
SInt:        4      -2147483648           2147483647
ULong:       8      0                     18446744073709551615
SLong:       8      -9223372036854775808  9223372036854775807
ULong Long:  8      0                     18446744073709551615
SLong Long:  8      -9223372036854775808  9223372036854775807
Run Code Online (Sandbox Code Playgroud)

因此,如您所见,您可以使数字远大于int32767。

一种方法如下:

double a=rand()/(double)RAND_MAX;
unsigned long long random_n=(unsigned long long)(BIG_MAXIMUM_NUMBER*a);
Run Code Online (Sandbox Code Playgroud)

但是,由于浮点数的离散性质,这可能意味着某些值永远不会出现在输出流中。

C++11 有一个库可以解决这个问题和你提到的问题。其用法的一个例子是:

const int min = 100000;
const int max = 1000000;
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(min,max);
int random_int = distribution(generator);
Run Code Online (Sandbox Code Playgroud)

只需更改数据类型即可满足您的大需求。

另一种看待这个问题的方法是,我们可以将其解释rand()为返回一个位字段,并且由于它是统一的 PRNG,因此所有位字段的可能性相同。然后,我们可以多次调用来rand()获取多个同样可能的位字段,并将它们合并以产生大数字。以下是我们如何从两个 8 位随机数生成 16 位随机数:

uint16 a=(uint16)(rand()&255);
uint16 b=(uint16)(rand()&255);
uint16 random_int=b<<8 | a;
Run Code Online (Sandbox Code Playgroud)

只保留返回的rand()&255数字的 8 个最低有效位rand();也就是说,它只保留 的最后一个字节rand()

将此(uint16)字节转换为无符号 16 位数字。

a<<8将 8 位的位a向左移动,从而为安全添加 留出空间b

但是,如果rand()返回一个有符号值,使得最高有效位始终为 0 或 1,该怎么办?然后我们可以执行以下操作:

uint16 a=(uint16)(rand()&255);
uint16 b=(uint16)(rand()&255);
uint16 c=(uint16)(rand()&1);
uint16 random_int=c<<14 | b<<7 | a;
Run Code Online (Sandbox Code Playgroud)

我们仅左移b7 位,以便第 8 个最低有效位是随机的。这意味着第 14 个和第 15 个最低有效位将是非随机的。由于我们想要模仿 的行为rand(),因此我们将第 15 个最低有效位保留为非随机的,并抓取一个随机位以左移到第 14 个 LSB 的位置。

  • 当您从 /sf/ask/945257001/#13503714 复制上述“uniform_int_distribution”的使用时,您删除了有关为生成器播种的注释。这可能很重要。 (2认同)
  • @BenjaminBannier,注释只是生成器应该正确播种。cstdlib 的“rand()”也应该如此。讨论这一点可能偏离这里的兴趣点。 (2认同)