src.it.unimi.dsi.util.XorGensRandomGenerator Maven / Gradle / Ivy
package it.unimi.dsi.util;
/*
* DSI utilities
*
* Copyright (C) 2012-2020 Sebastiano Vigna
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*
*/
import java.io.Serializable;
import it.unimi.dsi.Util;
import org.apache.commons.math3.random.AbstractRandomGenerator;
import org.apache.commons.math3.random.RandomGenerator;
/** A fast, high-quality 64-bit {@linkplain RandomGenerator pseudorandom number generator} described in “Some long-period random number generators using shift
* and xors”, ANZIAM Journal 48, C188−C202, 2007. */
public class XorGensRandomGenerator extends AbstractRandomGenerator implements Serializable {
private static final long serialVersionUID = 0L;
private static final int WLEN = 64;
private static final int R = 64;
private static final int S = 53;
private static final int A = 33;
private static final int B = 26;
private static final int C = 27;
private static final int D = 29;
private static final long WEYL = 0x61c8864680b583ebL;
/** State of the Xorshift generator. */
private long[] x = new long[R];
private long weyl;
private int i;
/** Creates a new generator, initializing its seed with {@link Util#randomSeed()}. */
public XorGensRandomGenerator() {
this(Util.randomSeed());
}
/** Creates a new generator using a given seed.
*
* @param seed a nonzero seed for the generator (if zero, the generator will be seeded with -1).
*/
public XorGensRandomGenerator(final long seed) {
setSeed(seed);
}
@Override
public void setSeed(long seed) {
long v = seed == 0 ? -1 : seed; /* v must be nonzero */
for (int k = WLEN; k > 0; k--) { /* Avoid correlations for close seeds */
v ^= v << 10;
v ^= v >>> 15; /* Recurrence has period 2**wlen-1 */
v ^= v << 4;
v ^= v >>> 13; /* for wlen = 32 or 64 */
}
for (int k = 0; k < R; k++) { /* Initialise circular array */
v ^= v << 10;
v ^= v >>> 15;
v ^= v << 4;
v ^= v >>> 13;
x[k] = v;
}
i = R - 1;
long t;
for (int k = 4 * R; k > 0; k--) { /* Discard first 4*r results */
t = x[i = (i + 1) & (R - 1)];
t ^= t << A;
t ^= t >>> B;
v = x[(i + (R - S)) & (R - 1)];
v ^= v << C;
v ^= v >>> D;
x[i] = t ^ v;
}
}
@Override
public long nextLong() {
long t, v;
t = x[i = (i + 1) & (R - 1)]; /* Assumes that r is a power of two */
v = x[(i + (R - S)) & (R - 1)]; /* Index is (i-s) mod r */
t ^= t << A;
v ^= v << C;
t ^= t >>> B; /* (I + L^a)(I + R^b) */
v ^= v >>> D; /* (I + L^c)(I + R^d) */
x[i] = (v ^= t); /* Update circular array */
weyl += WEYL;
return (v + (weyl ^ (weyl >>> 27)));
}
@Override
public int nextInt() {
return (int)nextLong();
}
@Override
public int nextInt(final int n) {
return (int)nextLong(n);
}
public long nextLong(final long n) {
if (n <= 0) throw new IllegalArgumentException();
// No special provision for n power of two: all our bits are good.
for(;;) {
final long bits = nextLong() >>> 1;
final long value = bits % n;
if (bits - value + (n - 1) >= 0) return value;
}
}
@Override
public double nextDouble() {
return (nextLong() >>> 11) * 0x1.0p-53;
}
@Override
public float nextFloat() {
return (nextLong() >>> 40) * 0x1.0p-24f;
}
@Override
public boolean nextBoolean() {
return nextLong() < 0;
}
@Override
public void nextBytes(final byte[] bytes) {
for (int i = bytes.length; i != 0;)
for (long bits = nextLong(), n = Math.min(i, 8); n-- != 0; bits >>= 8) bytes[--i] = (byte)bits;
}
}