I'm looking for an efficient algorithm that produces random values within a range, without repetitions.
In pseudo-code: (in class Rand)
Rand(long from, long to) {
this.from = from;
this.to = to;
// ...
}
long getNumber() {
// returns a random number in the [from, to] range
// which has never been returned before
}
Usage:
Rand r = new Rand(1, 100000000);
long x = r.getNumber();
long y = r.getNumber();
...
The numbers returned from r.getNumber() should always be different from the ones previously returned.
Of course, if to - from + 1
numbers were returned, the algorithm should start again (or fall in error - not important anyway).
Note that the range may be very large, and thus a randomly arranged array (containing initially [from, to]
numbers) is likely to overflow the memory.
@rossum said:
So even xor encryption or bitwise reverse would do for some purposes.
And here is a php function using xor and bitwise reverse as a simple 1-to-1 encryption.
It is a pseudo random number generator with guaranteed fill in of all values and no identical values. You supply n:0..63 and it provides a random 0..63.
It only accepts 2^i ranges, like 0..63, 0..127 etc.
Is not cryptographically safe etc, just random.
Such a function is extremely suitable for garbage collection routines, as it will not attempt to clean the same area twice, even though doing things randomly.
example output:
you can test the code here in php sandbox
And here is another one, but accepts any range, not only powers of 2.
example output:
related php sandbox is here
One way to do this would be to generate a list of numbers between from and to, removing these at random until the bag is empty, at which point it's re-populated. To save on storage for large ranges, you can record picked numbers up to a point (re-picking when a duplicate is chosen), since the probability of picking a duplicate should be low initially. Determining the optimal transition point will probably be an empirical exercise.
EDIT: Some more thoughts.
For truly huge ranges, not even that will provide good performance under the memory limitation. One idea might be to store the candidates not as a list of numbers, but as an interval. So, initially, you choose between from and to, getting x1. Next time, pick from a number from the first subinterval or the second, with probability in proportion to the interval length. At each step, eliminate intervals which have zero length. This requires storing M + 2 integers (in the worst case), where M is the number of draws, or N/2 asymptotically for large N (in the worst case), where N is the initial interval size. Somebody might double-check me, though.
If you don't require every number from the interval to appear eventually, you can use a linear congruental generator:
It's periodical, the new period begins when seed becomes equal to the initial value, and the length of the period depends on A and C choice.
Pros: O(1) time and space, cons: not every number from the interval will appear.
For intervals of length 2^m, take a look at http://en.wikipedia.org/wiki/Linear_feedback_shift_register I did not use it, but wikipedia says it is possible it to be maximum-length, i.e. you can have all numbers (except one) appear in the output.
Some thoughts for a starting point:
1) Supposes that you have a function f(x) which is a permutation on 1..N where N is larger than your range. If you apply it to x within the range it may produce an illegal value - one outside your range. You could define a permutation within your range by simply calling f again on the illegal value. You will eventually come to a legal value because the sequence x, f(x), f^2(x), f^3(x) must eventually cycle and if the worst comes to the worst it will come back in at x.
2) There are switching networks which allow you to produce all possible permutations on N objects for special N - one example is http://en.wikipedia.org/wiki/Clos_network#Bene.C5.A1_network_.28m_.3D_n_.3D_2.29 (Funny URL - Benes network). You can get an arbitrary permutation on N objects, where N may I think have to be a power of 2, by setting the switches at random. Since there will be K switches there are 2^K ways of setting them which means that you do not have M! permutations with equal probability but perhaps you won't mind this, or can minimise the non-randomness by repeating this multiple times, or something.
3) If you are prepared to achieve near-randomness by applying many different base permutations many different times you could try alternately adding mod N across the whole range and then splitting the range into sub-ranges and e.g. for some stretch of p-1 values within the range apply the permutation produced by multiplying by some k mode p. The hope would be that although each individual step is pretty basic by appling enough of them and making them diverse enough the result would be close to being random, especially if you chose the parameters at random.
I will pretend you are asking for a solution in R (according to tag). What you're trying to do is sample without replacement. In R, there's a function called
sample
. Here, I'm sampling a vector of 30 values (1, 2, 3... 30), and once I draw a number, it's not replaced. You can make this reproducible on other machines by setting a seed (seeset.seed
).I ran this a number of times to show the randomness.
You could proceed this way (in python):
Create a xrange and pick k random element from it and use it as a RanndomGenerator:
Your Generator will generate all number randomly from FROM to TO and fail when it has generated more than k numbers:
with this example you would get :
you get