Last active
June 13, 2021 10:05
-
-
Save unascribed/696fcd47d1667cbfbe96b2b2a3e29a39 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* To the extent possible under law, the author has dedicated all copyright | |
* and related and neighboring rights to this software to the public domain | |
* worldwide. This software is distributed without any warranty. | |
* | |
* See <http://creativecommons.org/publicdomain/zero/1.0/> | |
*/ | |
package com.unascribed.random; | |
import java.io.IOException; | |
import java.util.Random; | |
import java.util.concurrent.atomic.AtomicLong; | |
/** | |
* Implementation of Random based on the xoshiro256** RNG. No-dependencies | |
* Java port of the <a href="http://xoshiro.di.unimi.it/xoshiro256starstar.c">original C code</a>, | |
* which is public domain. This Java port is similarly dedicated to the public | |
* domain. | |
* <p> | |
* Individual instances are not thread-safe. Each thread must have its own | |
* instance which is not shared. | |
* | |
* @see <a href="http://xoshiro.di.unimi.it/">http://xoshiro.di.unimi.it/</a> | |
* @author David Blackman and Sebastiano Vigna <[email protected]> (original C code) | |
* @author Una Thompson <[email protected]> (Java port) | |
*/ | |
public class RandomXoshiro256StarStar extends Random { | |
private static final long serialVersionUID = -2837799889588687855L; | |
private static final AtomicLong uniq = new AtomicLong(System.nanoTime()); | |
private static final long nextUniq() { | |
return splitmix64_2(uniq.addAndGet(SPLITMIX1_MAGIC)); | |
} | |
public RandomXoshiro256StarStar() { | |
this(System.nanoTime()^nextUniq()); | |
} | |
public RandomXoshiro256StarStar(long seed) { | |
super(seed); | |
// super will call setSeed | |
} | |
public RandomXoshiro256StarStar(long s1, long s2, long s3, long s4) { | |
setState(s1, s2, s3, s4); | |
} | |
// used to "stretch" seeds into a full 256-bit state; also makes | |
// it safe to pass in zero as a seed | |
//// | |
// what generator is used here is unimportant, as long as it's | |
// from a different family, but splitmix64 happens to be an | |
// incredibly simple high-quality generator of a completely | |
// different family (and is recommended by the xoshiro authors) | |
private static final long SPLITMIX1_MAGIC = 0x9E3779B97F4A7C15L; | |
private static long splitmix64_1(long x) { | |
return (x + SPLITMIX1_MAGIC); | |
} | |
private static long splitmix64_2(long z) { | |
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9L; | |
z = (z ^ (z >> 27)) * 0x94D049BB133111EBL; | |
return z ^ (z >> 31); | |
} | |
@Override | |
public void setSeed(long seed) { | |
// update haveNextNextGaussian flag in super | |
super.setSeed(seed); | |
long sms = splitmix64_1(seed); | |
s0 = splitmix64_2(sms); | |
sms = splitmix64_1(sms); | |
s1 = splitmix64_2(sms); | |
sms = splitmix64_1(sms); | |
s2 = splitmix64_2(sms); | |
sms = splitmix64_1(sms); | |
s3 = splitmix64_2(sms); | |
} | |
public void setState(long s0, long s1, long s2, long s4) { | |
if (s0 == 0 && s1 == 0 && s2 == 0 && s4 == 0) | |
throw new IllegalArgumentException("xoshiro256** state cannot be all zeroes"); | |
this.s0 = s0; | |
this.s1 = s1; | |
this.s2 = s2; | |
this.s3 = s4; | |
} | |
// not called, implemented instead of just throwing for completeness | |
@Override | |
protected int next(int bits) { | |
return (int)(nextLong() & ((1L << bits) - 1)); | |
} | |
@Override | |
public int nextInt() { | |
return (int)nextLong(); | |
} | |
@Override | |
public int nextInt(int bound) { | |
return (int)nextLong(bound); | |
} | |
public long nextLong(long bound) { | |
if (bound <= 0) throw new IllegalArgumentException("bound must be positive"); | |
// clear sign bit for positive-only, modulo to bound | |
return (nextLong() & Long.MAX_VALUE) % bound; | |
} | |
@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() & 1) != 0; | |
} | |
@Override | |
public void nextBytes(byte[] buf) { | |
nextBytes(buf, 0, buf.length); | |
} | |
public void nextBytes(byte[] buf, int ofs, int len) { | |
if (ofs < 0) throw new ArrayIndexOutOfBoundsException("Offset "+ofs+" is negative"); | |
if (ofs >= buf.length) throw new ArrayIndexOutOfBoundsException("Offset "+ofs+" is greater than buffer length"); | |
if (ofs+len > buf.length) throw new ArrayIndexOutOfBoundsException("Length "+len+" with offset "+ofs+" is past end of buffer"); | |
int j = 8; | |
long l = 0; | |
for (int i = ofs; i < ofs+len; i++) { | |
if (j >= 8) { | |
l = nextLong(); | |
j = 0; | |
} | |
buf[i] = (byte)(l&0xFF); | |
l = l >>> 8L; | |
j++; | |
} | |
} | |
/* | |
* Writes an endless stream of random bytes generated by xoshiro256** to | |
* stdout. Useful for testing with suites such as dieharder. Was originally | |
* written to ensure my port is correct and didn't contain any obvious bugs, | |
* as the original xoshiro256** passes dieharder. | |
*/ | |
public static void main(String[] args) throws IOException { | |
byte[] bys = new byte[2048]; | |
RandomXoshiro256StarStar r = new RandomXoshiro256StarStar(); | |
while (true) { | |
r.nextBytes(bys); | |
System.out.write(bys); | |
System.out.flush(); | |
} | |
} | |
/* This is xoshiro256** 1.0, our all-purpose, rock-solid generator. It has | |
excellent (sub-ns) speed, a state (256 bits) that is large enough for | |
any parallel application, and it passes all tests we are aware of. | |
For generating just floating-point numbers, xoshiro256+ is even faster. | |
The state must be seeded so that it is not everywhere zero. If you have | |
a 64-bit seed, we suggest to seed a splitmix64 generator and use its | |
output to fill s. */ | |
private static long rotl(long x, int k) { | |
return (x << k) | (x >>> (64 - k)); | |
} | |
private long s0; | |
private long s1; | |
private long s2; | |
private long s3; | |
@Override | |
public long nextLong() { | |
long result_starstar = rotl(s1 * 5, 7) * 9; | |
long t = s1 << 17; | |
s2 ^= s0; | |
s3 ^= s1; | |
s1 ^= s2; | |
s0 ^= s3; | |
s2 ^= t; | |
s3 = rotl(s3, 45); | |
return result_starstar; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment