3

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.

NekoBit
  • 35
  • 5
  • 1
    Careful!!! c++ has different requirements on `rand` than c does. Using c, there's a guarantee that nothing other than calls to rand will advance through the sequence of pseudo-random numbers. Look at the 'compatibility' section of the following: http://www.cplusplus.com/reference/cstdlib/rand/ – enhzflep Apr 06 '20 at 03:05
  • 1
    If your class is the *only* code that uses `rand()` (i.e. all other code in your program goes through your class and doesn't call `srand()` or `rand()` directly) you could store all generated random values in a container. `get_random(index)` can then check against that container - if the `index` is valid, return the element from the container, otherwise generate more elements as needed in a loop, optionally store them in the container, and return the needed value. You could also separately pre-generate the random values to populate the container, and retrieve them later – Peter Apr 06 '20 at 03:22
  • @enhzflep Noted, although I never planned on using the C version – NekoBit Apr 06 '20 at 16:32
  • @NekoBit - yeah, I know. It was for precisely that reason that I mentioned it. There exists a possibility when using c++, that you don't get back the same sequence of numbers of each time. ;) – enhzflep Apr 07 '20 at 00:10

3 Answers3

1

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.

Windfish
  • 68
  • 7
1

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.

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

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));
}
miszcz2137
  • 894
  • 6
  • 18
  • This is a great answer (can't approve not enough rep), because I did not yet know about the random classes in the standard library, I looked into mersenne_twister_engine, actually ended up using default_random_engine because I heard it can be a little faster (not that I bet it will matter but I like speed) and optimized. – NekoBit Apr 07 '20 at 00:11
  • Keep in mind `default_random_engine` is completely implementation defined, though it shouldn't be a problem here. – miszcz2137 Apr 07 '20 at 18:43