自定义随机数生成器

时间:2014-01-05 16:26:18

标签: c# random unity3d

是否有可能获得极快但可靠(相同输入=相同输出,因此我无法使用时间)伪随机数发生器?我希望最终结果类似float NumGen( int x, int y, int seed );,以便根据这三个值创建0到1之间的随机数。我找到了几个随机数生成器,但我无法让它们工作,Unity附带的随机数生成器使用起来很慢。我必须每1米的地形对发电机进行大约9次调用,所以我真的不在乎它是否在统计上是完全随机的,只是它的工作非常快。有谁知道一种符合我需求的算法?谢谢:))

2 个答案:

答案 0 :(得分:2)

我认为你低估了System.Random课程。这是非常迅速的。我相信您的减速与每次调用Random方法时创建NumGen课程的新实例有关。

在我的快速测试中,我能够在大约1毫秒内使用System.Random生成100,000个随机数。

为避免减慢速度,请考虑2D平面中的种子点。分散种子点,使它们覆盖不超过100,000米的距离。然后关联(或计算)每个仪表的最近种子点,并将该点用作System.Random的种子。

是的,你将产生大量你永远不会使用的随机数字,但它们几乎是免费的。

的伪代码:

double NumGen(x, y, distance, seed) {
  Random random = new Random(seed);
  double result = 0;
  for (int i=0; i<distance; i++) {
    result = random.NextDouble();
  }
}

您可以修改此简单大纲以返回一系列随机数(可能表示网格),并将其与缓存机制相结合。这样可以节省内存并改善(减少)CPU消耗。

答案 1 :(得分:1)

我猜你必须在每次调用 NumGen 时创建一个 Random 实例。要使函数为相同的参数返回相同的数字,可以使用散列函数。

我测试了一些东西,这段代码比重新创建 Random 的内容快了大约3倍。

//System.Security.Cryptography
static MD5 hasher = MD5.Create();
static byte[] outbuf;
static byte[] inbuf = new byte[12];
static float floatHash(uint x, uint y, uint z) {
    inbuf[0]= (byte)(x >> 24);
    inbuf[1]=(byte)(x >> 16);
    inbuf[2]=(byte)(x >> 8);
    inbuf[3]=(byte)(x);
    inbuf[4]=(byte)(y >> 24);
    inbuf[5]=(byte)(y >> 16);
    inbuf[6]=(byte)(y >> 8);
    inbuf[7]=(byte)(y);
    inbuf[8]=(byte)(z >> 24);
    inbuf[9]=(byte)(z >> 16);
    inbuf[10]=(byte)(z >> 8);
    inbuf[11]=(byte)(z);
    outbuf = hasher.ComputeHash(inbuf);
    return ((float)BitConverter.ToUInt64(outbuf, 0))/ulong.MaxValue;
}

使用某些RSA方法的另一种方法比新的System.Random(种子)快约5倍:

static uint prime = 4294967291;
static uint ord = 4294967290;
static uint generator = 4294967279;
static uint sy;
static uint xs;
static uint xy;
static float getFloat(uint x, uint y, uint seed) {
    //will return values 1=> x >0; replace 'ord' with 'prime' to get 1> x >0
    //one call to modPow would be enough if all data fits into an ulong
    sy = modPow(generator, (((ulong)seed) << 32) + (ulong)y, prime);
    xs = modPow(generator, (((ulong)x) << 32) + (ulong)seed, prime);
    xy = modPow(generator, (((ulong)sy) << 32) + (ulong)xy, prime);
    return ((float)xy) / ord;
}
static ulong b;
static ulong ret;
static uint modPow(uint bb, ulong e, uint m) {
    b = bb;
    ret = 1;
    while (e > 0) {
        if (e % 2 == 1) {
            ret = (ret * b) % m;
        }
        e = e >> 1;
        b = (b * b) % m;
    }
    return (uint)ret;
}

我进行了测试以生成100000个浮点数。我使用索引作为System.Random的种子和floatHash的x参数(y和z为0)。

  

System.Random:Min:2.921559E-06 Max:0.9999979 Repetitions:0

     

floatHash MD5:Min:7.011156E-06 Max:0.9999931重复:210(值被返回两次)

     

getFloat RSA:Min:1.547858E-06 Max:0.9999989 Repetitions:190