创建一个随机序列,跳到序列的任何部分

时间:2010-05-04 21:41:28

标签: math random srand

在Linux中。有一个srand()函数,您可以在其中提供种子,并且在后续调用random()函数时它将保证相同的伪随机数序列。

让我们说,我想通过记住这个种子值来存储这个伪随机序列。

此外,假设我想在此伪随机序列中获得第10万个数字。

一种方法是使用srand()提供种子号,然后调用random()10万次,并记住这个数字。

是否有更好的方法可以跳过伪随机列表中的所有99,999个其他数字,并直接获取列表中的第10万个数字。

感谢,

4 个答案:

答案 0 :(得分:2)

我不确定在任何平台上实施rand是否有明确的标准;但是,从GNU Scientific Library中选择一个:

  

- 生成器:gsl_rng_rand

     

这是BSD rand生成器。它的顺序是

     

x n + 1 =(a x n + c)mod m

     

a = 1103515245,c = 12345且m = 2 31 。种子指定初始值x 1 。该发生器的周期为2 31 ,每个发生器使用1个字存储器。

所以要“知道”x n 要求你知道x n-1 。除非有一些明显的模式我缺少,否则你不能在没有计算它之前的所有值的情况下跳转到一个值。 (但每次rand实施都不一定如此。)

如果我们从x 1 ...

开始
  • x 2 =(a * x 1 + c)%m
  • x 3 =(a *((a * x 1 + c)%m)+ c)%m
  • x 4 =(a *((a *((a * x 1 + c)%m)+ c)%m)+ c)%m
  • x 5 =(a *(a *((a *((a * x 1 + c)%m)+ c)%m)+ c )%m)+ c)%m

它很快失控。这个功能容易减少吗?我认为不是。

(有一个系列的统计短语,其中x n 取决于x n-1 - 有人能提醒我这个词是什么吗?)< /子>

答案 1 :(得分:1)

如果它们在您的系统上可用,则可以使用rand_r代替rand&amp; srand,或initstatesetstate使用randomrand_runsigned *为参数,存储其状态。多次调用rand_r后,保存此无符号整数的值,并在下次将其用作起始值。

对于random(),请使用initstate而不是srandom。保存状态缓冲区的内容以用于要还原的任何状态。要恢复状态,请填写缓冲区并调用setstate。如果缓冲区已经是当前状态缓冲区,则可以跳过对setstate的调用。

答案 2 :(得分:1)

这是使用BSD rand()函数从@ Mark的答案开发的。

rand1()计算第n个随机数,从seed开始,经过n次计算。

rand2()使用快捷方式计算相同内容。它可以一次性升级到2 ^ 24-1步。在内部,它只需要24步。

如果BSD随机数生成器对你来说足够好,那么这就足够了:

#include <stdio.h>

const unsigned int m = (1<<31)-1;

unsigned int a[24] = {
    1103515245, 1117952617, 1845919505, 1339940641, 1601471041,
    187569281 , 1979738369, 387043841 , 1046979585, 1574914049,
    1073647617, 285024257 , 1710899201, 1542750209, 2011758593,
    1876033537, 1604583425, 1061683201, 2123366401, 2099249153,
    2051014657, 1954545665, 1761607681, 1375731713
};

unsigned int b[24] = {
    12345, 1406932606, 1449466924, 1293799192, 1695770928, 1680572000,
    422948032, 910563712, 519516928, 530212352, 98880512, 646551552,
    940781568, 472276992, 1749860352, 278495232, 556990464, 1113980928,
    80478208, 160956416, 321912832, 643825664, 1287651328, 427819008
};

unsigned int rand1(unsigned int seed, unsigned int n)
{
    int i;
    for (i = 0; i<n; ++i)
    {
        seed = (1103515245U*seed+12345U) & m;
    }
    return seed;
}

unsigned int rand2(unsigned int seed, unsigned int n)
{
    int i;
    for (i = 0; i<24; ++i)
    {
        if (n & (1<<i))
        {
            seed = (a[i]*seed+b[i]) & m;
        }
    }
    return seed;
}

int main()
{
    printf("%u\n", rand1 (10101, 100000));
    printf("%u\n", rand2 (10101, 100000));
}

适应任何线性同余发生器并不难。我用一种具有正确整数类型(Haskell)的语言计算了这些表,但是我可以用C语言中的另一种方式计算它们,只使用几行代码。

答案 3 :(得分:0)

如果您总是想要第100,000件商品,请将其存放以供日后使用。

或者您可以生成序列并存储...并稍后通过索引查询特定元素。