哪个伪随机函数生成的看似随机数在0到1之间?

时间:2019-05-20 09:15:15

标签: random parallel-processing random-seed pure-function

我能找到的大多数随机函数是一个序列函数,它将最后生成的结果保留为下一个调用的种子

我想要一个可以单独运行的纯函数,并且可以给定看似随机的序列(从头到尾任意数量)和种子

说实话,我希望算法仅在开始时使用随机种子并将每个元素的索引作为输入,才能并行生成随机数(并且可以在GPU中使用)

也许我可以使用哈希函数,但是我想知道哪种算法可以提供最可能的均匀分布,并且在给定任何种子和任何长度的情况下,看起来总是随机的

edit:谢谢您的所有建议。我对自己想要的东西有一个更扎实的想法

我不需要很多雪崩特性,但是我更关心均匀分布。而且要使其平行,它必须是无状态算法,因此大多数PRNG都不适合

但最不用担心的是安全性。我希望通过人类感知来获得一个看似随机的序列,但不要将其用于任何安全性,仅用于视觉和界面

如果算法非常快,将不胜感激

2 个答案:

答案 0 :(得分:2)

“纯”随机函数有几种选择。其中包括:

  • 哈希函数。
  • 使用输入作为种子的伪随机数生成器(PRNG)并返回其输出的函数。
  • 具有内部状态并输出随机数和新的内部状态的函数(此方法非常适合Haskell和其他函数式编程语言)。

另请参阅我的article on designs for PRNGs或L'Ecuyer,Munger等人的文章“并行计算机的随机数:要求和方法,重点放在GPU上”(2015年)。

对于要使用的hash functions,有多种选择,包括SHA-1,SHA-256,xxHash,MurmurHash3等。取决于您是否需要安全性以及其他因素,某些哈希函数可能比其他哈希函数更合适。

大多数散列函数输出一个位序列,但是不难看出如何将它们转换为数字-例如,请参见this question或我的article on numbers bounded by 0 and 1

答案 1 :(得分:1)

好的,这是关于这个问题的一些想法。

伪随机函数通常称为伪随机数生成器(PRNG)。

您可能会对[0 ... 1]范围内的双精度感兴趣,但是PRNG通常会生成单个64位(适合双精度)或32位(适合浮点)整数。转换为两倍,虽然不是很琐碎,但相当simple operation

典型的PRNG具有状态(由种子启动)和输出。对于最简单的PRNG(例如LCG)种子,状态和输出是同一回事,但通常情况并非如此。通常,状态的特征在于位数(例如,LCG为64位,梅森绞线为19937位)。

使用任何PRNG算法制作纯函数都非常简单-PRNG只是三个函数的集合,形式为

state_type make_state(seed_type seed) {
    // convert seeding to state, bits chopping
    return new_state;
}

state_type advance_state(state_type old_state) {
    // do bits chopping with old state
    // and advance to the next state
    return new_state;
}

uint64_t generate_output(state_type state) {
    // extract 64bits of randomness from state
    return new_random_number;
}

就是这样,PRNG中除了这些功能外没有其他内容。

还有,要解决的问题

  1. 您可以使用具有良好Avalanche properties的非加密哈希,这基本上意味着输入值的单个位更改(输入增加1)会导致输出大变化。快速,合理,可能不是很随机。 Murmur以及Mum hash都可以。

  2. 以计数器模式运行的加密密码。比选项1慢,但质量较高。相对大状态(例如512位左右)。我更喜欢ChaCha20-它众所周知,速度很快,请看代码here。选项1和2都假定您只是线性增加计数器作为输入。

  3. 另一个选择是使用PRNG,它具有对数复杂度超前功能。您可以从全局种子开始,如果您有2 10 CUDA内核,则第一个内核将使用种子,第二个内核将以2 64 / 2 向前跳10 = 2 54 ,其中复杂度为O(log 2 (N))的操作只有54次,第三个将比第二个多2个> 54 步骤和54操作等等。在已知的PRNG中,对数跃迁适用于LCG和PCG。我建议看一下PCG。

这意味着存在非平凡功能,形式为

state_type advance_state(state_type old_state, int64_t distance) {
    // non-trivial advance by distance
    // non-trivial means it is not just a loop, it is better than linear algorithm
    return new_state;
}