Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
108 lines (92 sloc) 2.99 KB
// see T. E. Hull and A. R. Dobell (1962). ‘Random number generators.’ Soc. Indust. Appl. Math. Rev. 4, 230–254.
public class VisitInDisorder {
int maxrange;
int prime;
int index;
int offset;
int runningvalue;
public VisitInDisorder(int range) {
if(range < 2) throw new IllegalArgumentException("Your range need to be greater than 1 "+range);
int min = range / 2 ;
maxrange = range;
prime = selectCoPrimeResev(min, range);
offset = java.util.concurrent.ThreadLocalRandom.current().nextInt(range);
index = 0;
runningvalue = offset;
}
// computed the long way
private int getCurrentValue() {
return (int)(( (long) index * prime + offset ) % ( maxrange));
// the multiplication and the modulo could be optimized away with
// some work
}
public boolean hasNext() {
return index < maxrange;
}
public int next() {
runningvalue += prime;
if(runningvalue >= maxrange) runningvalue -= maxrange;
index ++;
// next line can be safely uncommented
//if(runningvalue != getCurrentValue()) throw new RuntimeException("bug");
return runningvalue;
}
public static void main(String[] args) {
int N = args.length > 0 ? Integer.parseInt(args[0]): 32;
VisitInDisorder vid = new VisitInDisorder(N);
System.out.println("initialized...");
System.out.println("Generating values between 0 and "+N+" in random order");
java.util.HashSet<Integer> checker = new java.util.HashSet<Integer>();
while(vid.hasNext()) {
int n = vid.next();
if(n < 0) throw new RuntimeException("negative");
if(n >= N) throw new RuntimeException("too big");
checker.add(n);
System.out.print(n + " ");
}
System.out.println();
if(N != checker.size()) throw new RuntimeException("bad set size");
System.out.println("ok");
}
final static int MAX_COUNT = 100000;
static int selectCoPrimeResev(int min, int target) {
int count = 0;
int selected = 0;
java.util.concurrent.ThreadLocalRandom rand = java.util.concurrent.ThreadLocalRandom.current();
for(int val = min; val < target; ++val) {
if(coprime(val,target)) {
count += 1;
if((count == 1) || ( rand.nextInt(count) < 1 )) {
selected = val;
}
};
if(count == MAX_COUNT) return val;
}
return selected;
}
static boolean coprime(int u, int v) {
return gcd(u,v) == 1;
}
static int gcd(int u, int v) {
int shift;
if (u == 0) return v;
if (v == 0) return u;
for (shift = 0; ((u | v) & 1) == 0; ++shift) {
u >>= 1;
v >>= 1;
}
while ((u & 1) == 0)
u >>= 1;
do {
while ((v & 1) == 0)
v >>= 1;
if (u > v) {
int t = v;
v = u;
u = t;
}
v = v - u;
} while (v != 0);
return u << shift;
}
}