Search code examples
c#randomnoise

Deterministic random noise generator from multiple 64-bit inputs?


I am trying to create a pseudo-random number generator in C# that produces the same output, given the same set of inputs. It needs to be fast, accept 64 bit numbers and, particularly important allow an arbitrary set of inputs. The output should be a double between [0 and 1}.

The inputs, for the most part will be a seed value that stays constant during the lifetime of the app, and one or more other numeric values, such as an x, y, z and w coordinate, which may themselves be of type int32, int64 or double.

I've tried adapting some other random number generators I found, but I keep getting massive problems with clumping, mainly due to the fact that I have no idea about the theory surrounding the topic, or the mathematical properties of prime numbers, which seem to play a role in most cases.

I want to use this function for generating the random noise that will be used internally within a number of other algorithms, including my own, and standard algorithms such as Perlin noise, amongst others.

How should I go about this?


Solution

  • This is still a pretty slow rng, but approximately 10 times faster than the Murmur3 based. Reseeding for every generated number has a cost, so does requiring a large number of seeds that all have a non-systematic influence on the outcome.

    Update: There really isn't any reason to allow weak bits, this version should have no obvious patterns.

    class Prng
    {
        const double shift3 = .125;
        const double shift9 = shift3 * shift3 * shift3;
        const double shift27 = shift9 * shift9 * shift9;
        const double shift53 = shift27 * shift27 * 2.0;
        public ulong rndlong(ulong a, ulong b, ulong c, ulong d){
            ulong e = ((a ^ (b >> 14 | b << 50)) + ((c >> 31 | c << 33) ^ (d >> 18 | d << 46)))*1911413418482053185;
            ulong f = (((a >> 30 | a << 34) ^ c) + ((b >> 32 | b << 32) ^ (d >> 50 | d << 14)))*1139072524405308145;
            ulong g = (((a >> 49 | a << 15) ^ (d >> 33 | d << 31)) + (b ^ (c >> 48 | c << 16)))*8792993707439626365;
            ulong h = (((a >> 17 | a << 47) ^ (b >> 47 | b << 17)) + ((c >> 15 | c << 49) ^ d))*1089642907432013597;
            return (e ^ f ^ (g >> 21 | g << 43) ^ (h >> 44 | h << 20)) * 2550117894111961111 +
                ((e >> 20 | e << 44) ^ (f >> 41 | f << 23) ^ (g >> 42 | g << 22) ^ h) * 8786584852613159497 +
                ((e >> 43 | e << 21) ^ (f >> 22 | f << 42) ^ g ^ (h >> 23 | h << 41)) * 3971056679291618767;
        }
        public double rnddouble(ulong a, ulong b, ulong c, ulong d)
        {
            return (double)(rndlong(a, b, c, d) >> 11) * shift53;
        }
    }