Best method of getting a random number at an "index" from a seed?

Viewed 460

I was wanting to know a good way of getting a random number from an index. Basically, here is an example of what I want.

From what I know on how std::rand() / rand() works, it just gives you a random number each time it's called, and each time you reset a seed by calling std::srand it gives out the same exact numbers. But the way rand works seems very global, meaning that each time you call it, the number changes by some index of one from the original seed (I know that isn't exactly how it works under the hood though)

// User manually provides a seed, not by std::time(nullptr)
get_random(3); // Return 1641
get_random(67); // returns 2782
get_random(5); // return 9832
get_random(67); // return 2782

Notice that if I repeat an index, I still get the same result from the seed each time. I put a little bit of thought into it and this was my best result

int Class::get_random(int index) {
    std::srand(user_provided_seed); // reset the seed
    for (int i = 0; i < index; i++) {
        std::rand();
    }
    return std::rand();
}

The above works fine, basically it just expects a random number as an index and works with this number, but I feel like the above does a bit too much work, in my program I actually do expect the user to pass in a pretty large index, around the 1000s, and I feel like simply calling std::rand() 1000 times wastes CPU time.

Is there a better way to do this? Perhaps there is already a function included that does what I need it to. Also note that I do not need true random numbers and pseudo random numbers is perfect for my case.

3 Answers

If rand() is recursive there may not be another way. In that case every next number in the random sequence is computed based on the previous and therefore rand() must be executed every time. I am not sure if rand() is recursive though - you may want to examine that possibility before worrying about a better solution.

Your approach in get_random is the best you can do.

The C standard requires rand to output the same sequence of numbers for a given seed. However, even if the seed is given, the C standard doesn't specify exactly what that sequence is. Notably:

  • rand uses an unspecified algorithm to generate pseudorandom numbers, and that algorithm can differ between C implementations, including versions of the same standard library.
  • rand returns values no greater than RAND_MAX, and RAND_MAX can differ between C implementations.

See also this question.

There are couple ways. First as @Peter said in comment store random values (works if nobody else uses std::rand or you can create your own std::random_engine).

Class {
    ...
    std::vector<int> values;
    std::mersenne_twister_engine engine;
}
int Class::get_random(int index) {
    for (int i = values.size(); i <= index; i++) {
        values.push_back(engine());
    }
    return values[index];
}

Or you can you pseudorandom function that can be counted for index separately. For example (in pseudocode because afaik there is no sha in standard library):

int get_random(int index) {
    return (int)(sha256(str(seed) +  str(index));
}
Related