用于程序内容的快速伪随机数生成器

时间:2008-10-03 16:25:35

标签: c++ x86 random

我正在寻找一个伪随机数生成器,它可以专门在生成每个数字之前给定种子时快速工作。到目前为止,我见过的大多数生成器都假设您设置一次种子,然后生成一长串数字。到目前为止,我看到的唯一类似于Perlin Noise的东西,但是它产生了太“平滑”的数据 - 对于类似的输入,它往往产生类似的结果。

生成器的声明应该类似于:

int RandomNumber1(int seed);

或者:

int RandomNumber3(int seedX, int seedY, int seedZ);

我认为拥有良好的RandomNumber1应该足够了,因为可以通过对其输入进行散列并将结果传递给RandomNumber1来实现RandomNumber3,但我编写了第二个原型,以防某些实现可以使用独立输入。

此生成器的预期用途是将其用于程序内容生成器,例如通过将树放置在网格中来生成林,并确定每个位置的随机树种和随机空间偏移。

生成器需要非常高效(低于500个CPU周期),因为在渲染过程中会实时大量创建过程内容。

6 个答案:

答案 0 :(得分:20)

好像你要求哈希函数而不是PRNG。谷歌搜索“快速哈希函数”产生了几个看起来很有希望的结果。

For example

uint32_t hash( uint32_t a)
    a = (a ^ 61) ^ (a >> 16);
    a = a + (a << 3);
    a = a ^ (a >> 4);
    a = a * 0x27d4eb2d;
    a = a ^ (a >> 15);
    return a;
}

编辑:是的,有些哈希函数看起来比其他函数更合适。

出于您的目的,应该足以观察功能,并检查输入中的单位变化是否会传播到大量输出位。

答案 1 :(得分:9)

是的,您正在寻找快速整数哈希算法而不是PRNG。

这个page有一些算法,我相信你现在可以找到更多的算法,而且你知道正确的搜索词。

修改:原始页面已被删除,实时版本可为found on GitHub

答案 2 :(得分:5)

这是George Marsaglia开发的一个小型随机数发生器。他是该领域的专家,因此您可以确信发电机具有良好的统计特性。

v = 36969*(v & 65535) + (v >> 16);
u = 18000*(u & 65535) + (u >> 16);
return (v << 16) + u;

这里你和v是无符号整数。将它们初始化为任何非零值。每次生成随机数时,请将u和v存储在某处。你可以将它包装在一个函数中,以匹配上面的签名(除了int是无符号的。)

答案 3 :(得分:2)

请参阅std::tr1::ranlux3或其他随机数生成器,这些生成器是标准C ++库中TR1添加的一部分。我最初建议mt19937,但后来看到你的注意事项,它需要非常快。 TR1应该在Microsoft VC++和GCC上可用,也可以在支持更多编译器的boost库中找到。

示例改编自boost documentation

#include <random>
#include <iostream>
#include <iterator>
#include <functional>
#include <algorithm>
#include <ctime>
using namespace std;
using namespace std::tr1;
int main(){
    random_device trueRand;
    ranlux3 rng(trueRand);  // produces randomness out of thin air
                            // see pseudo-random number generators
    uniform_int<> six(1,6); // distribution that maps to 1..6
                            // see random number distributions
    variate_generator<ranlux3&, uniform_int<> >
           die(rng, six);   // glues randomness with mapping

    // simulate rolling a die
    generate_n( ostream_iterator<int>(cout, " "), 10, ref(die));
}

示例输出:

2 4 4 2 4 5 4 3 6 2

任何TR1随机数生成器都可以播种任何其他随机数生成器。如果您需要更高质量的结果,请考虑将mt19937的输出(速度较慢但质量较高)输入minstd_rand或randlux3,它们是更快的发生器。

答案 4 :(得分:0)

如果内存不是真正的问题而且速度至关重要,那么你可以预先建立一大堆随机数,并在运行时迭代它。例如,有一个单独的程序生成100,000个随机数,并将其保存为自己的文件,如

unsigned int randarray [] = {1,2,3,....}

然后将该文件包含到您的编译中,并且在运行时,您的随机数函数只需要从该数组中提取数字,并在它到达结束时循环回到开始。

答案 5 :(得分:0)

我在Java随机数库中使用以下代码 - 这对我来说非常有用。我也用它来生成程序内容。

/**
 * State for random number generation
 */
private static volatile long state=xorShift64(System.nanoTime()|0xCAFEBABE);

/**
 * Gets a long random value
 * @return Random long value based on static state
 */
public static long nextLong() {
    long a=state;
    state = xorShift64(a);
    return a;
}

/**
 * XORShift algorithm - credit to George Marsaglia!
 * @param a initial state
 * @return new state
 */
public static final long xorShift64(long a) {
    a ^= (a << 21);
    a ^= (a >>> 35);
    a ^= (a << 4);
    return a;
}