Random.Next() – finding the Nth .Next()

| | August 8, 2015

Given a consistently seeded Random:

Random r = new Random(0);

Calling r.Next() consistently produces the same series; so is there a way to quickly discover the N-th value in that series, without calling r.Next() N times?

My scenario is a huge array of values created via r.Next(). The app occasionally reads a value from the array at arbitrary indexes. I’d like to optimize memory usage by eliminating the array and instead, generating the values on demand. But brute-forcing r.Next() 5 million times to simulate the 5 millionth index of the array is more expensive than storing the array. Is it possible to short-cut your way to the Nth .Next() value, without / with less looping?

4 Responses to “Random.Next() – finding the Nth .Next()”

  1. You could build your own on-demand dictionary of ‘indexes’ & ‘random values’. This assumes that you will always ‘demand’ indexes in the same order each time the program runs or that you don’t care if the results are the same each time the program runs.

    Random rnd = new Random(0);
    Dictionary<int,int> randomNumbers = new Dictionary<int,int>();
    int getRandomNumber(int index)
        if (!randomNumbers.ContainsKey(index))
            randomNumbers[index] = rnd.Next();
        return randomNumbers[index];
  2. In theory if you knew the exact algorithm and the initial state you’d be able to duplicate the series but the end result would just be identical to calling r.next().

    Depending on how ‘good’ you need your random numbers to be you might consider creating your own PRNG based on a Linear congruential generator which is relatively easy/fast to generate numbers for. If you can live with a “bad” PRNG there are likely other algorithms that may be better to use for your purpose. Whether this would be faster/better than just storing a large array of numbers from r.next() is another question.

  3. Gareth McCaughan on November 30, -0001 @ 12:00 AM

    No, I don’t believe there is. For some RNG algorithms (such as linear congruential generators) it’s possible in principle to get the n’th value without iterating through n steps, but the Random class doesn’t provide a way of doing that.

    I’m not sure whether the algorithm it uses makes it possible in principle — it’s a variant (details not disclosed in documentation) of Knuth’s subtractive RNG, and it seems like the original Knuth RNG should be equivalent to some sort of polynomial-arithmetic thing that would allow access to the n’th value, but (1) I haven’t actually checked that and (2) whatever tweaks Microsoft have made might break that.

    If you have a good enough “scrambling” function f then you can use f(0), f(1), f(2), … as your sequence of random numbers, instead of f(0), f(f(0)), f(f(f(0))), etc. (the latter being roughly what most RNGs do) and then of course it’s trivial to start the sequence at any point you please. But you’ll need to choose a good f, and it’ll probably be slower than a standard RNG.

  4. I don’t know the details of the PRNG used in the BCL, but my guess is that you will find it extremely difficult / impossible to find a nice, closed-form solution for N-th value of the series.

    How about this workaround:

    Make the seed to the random-number generator the desired index, and then pick the first generated number. This is equally ‘deterministic’, and gives you a wide range to play with in O(1) space.

    static int GetRandomNumber(int index)
        return new Random(index).Next();

Leave a Reply