0

Most random function I could find is a sequence function, it keep the last generated result as a seed of the next call

I want a pure function that could be run on its own and could give seemingly random sequence given any number from start to end and a seed

To be honest I want an algorithm to generate random number in parallel (and could be used in GPU) only with a random seed at start and index of each element as an input

Maybe I could use a hash function but I would like to know which algorithm could give the most possible uniform distribution and always seemingly random given any seed and any length

edit : thanks you for you all suggestion. I have a more solid idea of what I want which I could explain

I don't need much avalanche property but instead I care more about uniform distribution. And for it to be parallel it must be a stateless algorithm, so most PRNG is not fit

But what the least concern is security. I want a seemingly random sequence by human perception but don't use it in any security, just for visual and interface

And will be more grateful if it is a very fast algorithm

Thaina Yu
  • 1,372
  • 2
  • 16
  • 27

2 Answers2

3

There are several choices for "pure" random functions. They include:

  • A hash function.
  • A function that seeds a pseudorandom number generator (PRNG) with its input and returns that PRNG's output.
  • A function that takes an internal state and outputs random numbers and a new internal state (this approach is well-suited for Haskell and other functional programming languages).

See also my article on designs for PRNGs or the article "Random Numbers for Parallel Computers: Requirements and Methods, With Emphasis on GPUs" (2015), by L'Ecuyer, Munger, and others.

As for which hash functions to use, there are various choices, including SHA-1, SHA-256, xxHash, MurmurHash3, and others; some hash functions may be more appropriate than others depending on whether you require security, among other factors.

Most hash functions output a sequence of bits, but it's not hard to see how they can be converted to numbers — see this question or my article on numbers bounded by 0 and 1, for example.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
1

Ok, here are some thoughts on the problem.

Fake random function is usually called Pseudo Random Numbers Generators (PRNG).

You might be interested in doubles in [0...1) range, but PRNG usually generates single 64bit (good for double) or 32bit (good for float) integer number. Conversion to double, while not quite trivial, is rather simple operation.

Typical PRNG has state, initiated with seed, and output. For simplest PRNGs (like LCG) seed, state and output are the same thing, but it is not true in general. Usually state is characterized by number of bits (say, 64bits for LCG up to 19937bits for Mersenne twister).

Making pure functions from any PRNG algorithm is rather simple - PRNG is just a set of three functions in the form of

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;
}

And that is it, there is nothing more in the PRNG beyond those functions.

And, to the question at hands

  1. You could use non-crypto hash with good Avalanche properties, basically meaning single bit change in input value (input increased by 1) cause big changein output. Fast, reasonable, might be not very random. Murmur is ok, as well as Mum hash.

  2. Crypto cipher running in the counter mode. Slower than option 1, but high quality numbers. Relative large state (say 512bits or so). I prefer ChaCha20 - it is well-known, reasonable fast, take a look at code here. Both option 1 and 2 assume you have just linearly increasing counter as input.

  3. Another option is using PRNG which has logarithmic complexity jump ahead function. This you could start with global seed, and if you have 210 CUDA cores, your first core will use seed, second will jump ahead by 264/210=254, which with O(log2(N)) complexity is only 54 operations, third will jump ahead of second by another 254 steps and 54 operations and so on and so forth. Out of known PRNGs logarihmic jump ahead works for LCG as well as PCG. I would recommend to look at PCG.

It means there is non-trivial function in the form of

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;
}
Severin Pappadeux
  • 18,636
  • 3
  • 38
  • 64