Mega Code Archive

 
Categories / Java / Development Class
 

A linear random method based on xor shifts

//package com.studiofortress.sf.util; import java.util.Random; /**  * a linear random method based on xor shifts--which is a fast way to do LFSR  * --ie one clock per bit is slow. This is faster per step that java Random.  *  * This does better than LCC generators (ie passes the monkey tests and DNA  * tests where LCG dont). In other words it does not have the hyperplane  * problem.  *  * This has a period of 2**128-1. This is quite easy to prove as follows.  *  * the counter can be shown to be a LFSR with period 2**64-1. However we have a  * simple counter in the stepped variable. That is after 2**64 counts stepped  * mod 2**64 == 0. Hence the phase is shifted by one and the period of stepped  * and counter are relatively prime. We combine them with Addition, which is  * slightly nonlinear due to carry. Of course we could just use a simple ++  * counter. But thats boring.  *  * We could use * for this as well and have a stronger condition for non  * lineararity.  *  * We speed up the nextDouble function as well.  *  * @author bob - http://www.javagaming.org/index.php/topic,18426.0.html  */ final class Random64 extends Random {   private static final double LONG_2_DOUBLE =1.0 / (double)(1L<<53);   private static final long MASK_53=(1l<<53)-1;   private static final long serialVersionUID =-6678124822567014769L;   private static final long PRIME =0xd4d6712ee634312dl;   private long counter ;   private long stepped ;   public Random64() {     super();                 setSeed(System.nanoTime());   }   public Random64(long seed) {     super(seed);     setSeed(seed);   }   private void step(){     counter ^=(counter << 21);     counter ^=(counter >>> 35);     counter ^=(counter << 4);     stepped +=PRIME;   }   /**    * could use all 64 bits over 2 calls?    */   @Override   protected int next(int bits) {     step();     // Hate the dumb mask     return (int) (((counter + stepped) >>> 31) & ((1l << bits) - 1));   }   @Override   public void setSeed(long seed) {     counter =seed;     if (counter == 0)       counter =1;                 stepped=0;                 step();                 step();                 step();                 stepped=0;   }   /**    * uses only 32 bits of precision.    */   @Override   public double nextDouble() {     step();     return ((counter+stepped) & MASK_53)*LONG_2_DOUBLE;   }   @Override   public long nextLong() {     step();     return counter+stepped;   } }