Random64.java Source code

Java tutorial

Introduction

Here is the source code for Random64.java

Source

//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;
    }
}