new RNG for everything; Joise update

This commit is contained in:
minjaesong
2018-10-27 00:03:06 +09:00
parent 0c289b870f
commit dd36d3cb5f
10 changed files with 408 additions and 64 deletions

View File

@@ -0,0 +1,192 @@
package net.torvald.random;
import java.util.Random;
/**
* Xoroshift128
*
* see https://github.com/SquidPony/SquidLib/blob/master/squidlib-util/src/main/java/squidpony/squidmath/XoRoRNG.java
*/
public class HQRNG extends Random {
private static final long DOUBLE_MASK = (1L << 53) - 1;
private static final double NORM_53 = 1. / (1L << 53);
private static final long FLOAT_MASK = (1L << 24) - 1;
private static final double NORM_24 = 1. / (1L << 24);
private static final long serialVersionUID = 1018744536171610262L;
private long state0, state1;
public long getState0() {
return state0;
}
public long getState1() {
return state1;
}
/**
* Creates a new generator seeded using four calls to Math.random().
*/
public HQRNG() {
this((long) ((Math.random() - 0.5) * 0x10000000000000L)
^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L),
(long) ((Math.random() - 0.5) * 0x10000000000000L)
^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L));
}
/**
* Constructs this XoRoRNG by dispersing the bits of seed using {@link #setSeed(long)} across the two parts of state
* this has.
* @param seed a long that won't be used exactly, but will affect both components of state
*/
public HQRNG(final long seed) {
setSeed(seed);
}
/**
* Constructs this XoRoRNG by calling {@link #setSeed(long, long)} on the arguments as given; see that method for
* the specific details (stateA and stateB are kept as-is unless they are both 0).
* @param stateA the number to use as the first part of the state; this will be 1 instead if both seeds are 0
* @param stateB the number to use as the second part of the state
*/
public HQRNG(final long stateA, final long stateB) {
setSeed(stateA, stateB);
}
@Override
public final int next(int bits) {
final long s0 = state0;
long s1 = state1;
final int result = (int)(s0 + s1) >>> (32 - bits);
s1 ^= s0;
state0 = (s0 << 55 | s0 >>> 9) ^ s1 ^ (s1 << 14); // a, b
state1 = (s1 << 36 | s1 >>> 28); // c
return result;
}
@Override
public final long nextLong() {
final long s0 = state0;
long s1 = state1;
final long result = s0 + s1;
s1 ^= s0;
state0 = (s0 << 55 | s0 >>> 9) ^ s1 ^ (s1 << 14); // a, b
state1 = (s1 << 36 | s1 >>> 28); // c
/*
state0 = Long.rotateLeft(s0, 55) ^ s1 ^ (s1 << 14); // a, b
state1 = Long.rotateLeft(s1, 36); // c
*/
return result;
}
/**
* Can return any int, positive or negative, of any size permissible in a 32-bit signed integer.
* @return any int, all 32 bits are random
*/
public int nextInt() {
return (int)nextLong();
}
/**
* Exclusive on the outer bound; the inner bound is 0. The bound may be negative, which will produce a non-positive
* result.
* @param bound the outer exclusive bound; may be positive or negative
* @return a random int between 0 (inclusive) and bound (exclusive)
*/
public int nextInt(final int bound) {
return (int) ((bound * (nextLong() >>> 33)) >> 31);
}
/**
* Inclusive lower, exclusive upper.
* @param inner the inner bound, inclusive, can be positive or negative
* @param outer the outer bound, exclusive, should be positive, should usually be greater than inner
* @return a random int that may be equal to inner and will otherwise be between inner and outer
*/
public int nextInt(final int inner, final int outer) {
return inner + nextInt(outer - inner);
}
/**
* Exclusive on the outer bound; the inner bound is 0. The bound may be negative, which will produce a non-positive
* result.
* @param bound the outer exclusive bound; may be positive or negative
* @return a random long between 0 (inclusive) and bound (exclusive)
*/
public long nextLong(long bound) {
long rand = nextLong();
final long randLow = rand & 0xFFFFFFFFL;
final long boundLow = bound & 0xFFFFFFFFL;
rand >>>= 32;
bound >>= 32;
final long z = (randLow * boundLow >> 32);
long t = rand * boundLow + z;
final long tLow = t & 0xFFFFFFFFL;
t >>>= 32;
return rand * bound + t + (tLow + randLow * bound >> 32) - (z >> 63) - (bound >> 63);
}
/**
* Inclusive inner, exclusive outer; both inner and outer can be positive or negative.
* @param inner the inner bound, inclusive, can be positive or negative
* @param outer the outer bound, exclusive, can be positive or negative and may be greater than or less than inner
* @return a random long that may be equal to inner and will otherwise be between inner and outer
*/
public long nextLong(final long inner, final long outer) {
return inner + nextLong(outer - inner);
}
public double nextDouble() {
return (nextLong() & DOUBLE_MASK) * NORM_53;
}
public float nextFloat() {
return (float) ((nextLong() & FLOAT_MASK) * NORM_24);
}
public boolean nextBoolean() {
return nextLong() < 0L;
}
public void nextBytes(final byte[] bytes) {
int i = bytes.length, n = 0;
while (i != 0) {
n = Math.min(i, 8);
for (long bits = nextLong(); n-- != 0; bits >>>= 8) {
bytes[--i] = (byte) bits;
}
}
}
/**
* Sets the seed of this generator using one long, running that through LightRNG's algorithm twice to get the state.
* @param seed the number to use as the seed
*/
public void setSeed(final long seed) {
long state = seed + 0x9E3779B97F4A7C15L,
z = state;
z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
state0 = z ^ (z >>> 31);
state += 0x9E3779B97F4A7C15L;
z = state;
z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
state1 = z ^ (z >>> 31);
}
/**
* Sets the seed of this generator using two longs, using them without changes unless both are 0 (then it makes the
* state variable corresponding to stateA 1 instead).
* @param stateA the number to use as the first part of the state; this will be 1 instead if both seeds are 0
* @param stateB the number to use as the second part of the state
*/
public void setSeed(final long stateA, final long stateB) {
state0 = stateA;
state1 = stateB;
if((stateA | stateB) == 0L)
state0 = 1L;
}
}

View File

@@ -1,4 +1,4 @@
package net.torvald.random
/*package net.torvald.random
import net.torvald.terrarum.serialise.toLittle
import net.torvald.terrarum.serialise.toLittleLong
@@ -6,41 +6,178 @@ import org.apache.commons.codec.digest.DigestUtils
import java.util.Random
/**
* Xorshift128+
* Xoroshift128
*
* @see https://github.com/SquidPony/SquidLib/blob/master/squidlib-util/src/main/java/squidpony/squidmath/XoRoRNG.java
*/
class HQRNG @JvmOverloads constructor(seed: Long = System.nanoTime()) : Random() {
class HQRNG() : Random() {
var s0: Long; private set
var s1: Long; private set
private val DOUBLE_MASK = (1L shl 53) - 1
private val NORM_53 = 1.0 / (1L shl 53)
private val FLOAT_MASK = (1L shl 24) - 1
private val NORM_24 = 1.0 / (1L shl 24)
constructor(s0: Long, s1: Long) : this() {
this.s0 = s0
this.s1 = s1
var state0: Long = 0L; private set
var state1: Long = 0L; private set
/**
* Creates a new generator seeded using four calls to Math.random().
*/
init {
reseed(((Math.random() - 0.5) * 0x10000000000000L).toLong() xor ((Math.random() - 0.5) * 2.0 * -0x8000000000000000L).toLong(),
((Math.random() - 0.5) * 0x10000000000000L).toLong() xor ((Math.random() - 0.5) * 2.0 * -0x8000000000000000L).toLong())
}
init {
if (seed == 0L)
throw IllegalArgumentException("Invalid seed: cannot be zero")
/**
* Constructs this XoRoRNG by dispersing the bits of seed using [.setSeed] across the two parts of state
* this has.
* @param seed a long that won't be used exactly, but will affect both components of state
*/
constructor(seed: Long): this() {
setSeed(seed)
}
val hash = DigestUtils.sha256(seed.toString())
/**
* Constructs this XoRoRNG by calling [.setSeed] on the arguments as given; see that method for
* the specific details (stateA and stateB are kept as-is unless they are both 0).
* @param stateA the number to use as the first part of the state; this will be 1 instead if both seeds are 0
* @param stateB the number to use as the second part of the state
*/
constructor(stateA: Long, stateB: Long): this() {
reseed(stateA, stateB)
}
s0 = hash.copyOfRange(0, 8).toLittleLong()
s1 = hash.copyOfRange(8, 16).toLittleLong()
public override fun next(bits: Int): Int {
val s0 = state0
var s1 = state1
val result = (s0 + s1).toInt().ushr(32 - bits)
s1 = s1 xor s0
state0 = s0 shl 55 or s0.ushr(9) xor s1 xor (s1 shl 14) // a, b
state1 = s1 shl 36 or s1.ushr(28) // c
return result
}
override fun nextLong(): Long {
var x = s0
val y = s1
s0 = y
x = x xor (x shl 23)
s1 = x xor y xor (x ushr 17) xor (y ushr 26)
return s1 + y
val s0 = state0
var s1 = state1
val result = s0 + s1
s1 = s1 xor s0
state0 = s0 shl 55 or s0.ushr(9) xor s1 xor (s1 shl 14) // a, b
state1 = s1 shl 36 or s1.ushr(28) // c
/*
state0 = Long.rotateLeft(s0, 55) ^ s1 ^ (s1 << 14); // a, b
state1 = Long.rotateLeft(s1, 36); // c
*/
return result
}
fun serialize() = s0.toLittle() + s1.toLittle()
fun reseed(s0: Long, s1: Long) {
this.s0 = s0
this.s1 = s1
/**
* Exclusive on the outer bound; the inner bound is 0. The bound may be negative, which will produce a non-positive
* result.
* @param bound the outer exclusive bound; may be positive or negative
* @return a random int between 0 (inclusive) and bound (exclusive)
*/
override fun nextInt(bound: Int): Int {
return (bound * nextLong().ushr(33) shr 31).toInt()
}
}
/**
* Inclusive lower, exclusive upper.
* @param inner the inner bound, inclusive, can be positive or negative
* @param outer the outer bound, exclusive, should be positive, should usually be greater than inner
* @return a random int that may be equal to inner and will otherwise be between inner and outer
*/
fun nextInt(inner: Int, outer: Int): Int {
return inner + nextInt(outer - inner)
}
/**
* Exclusive on the outer bound; the inner bound is 0. The bound may be negative, which will produce a non-positive
* result.
* @param bound the outer exclusive bound; may be positive or negative
* @return a random long between 0 (inclusive) and bound (exclusive)
*/
fun nextLong(bound: Long): Long {
var bound = bound
var rand = nextLong()
val randLow = rand and 0xFFFFFFFFL
val boundLow = bound and 0xFFFFFFFFL
rand = rand ushr 32
bound = bound shr 32
val z = randLow * boundLow shr 32
var t = rand * boundLow + z
val tLow = t and 0xFFFFFFFFL
t = t ushr 32
return rand * bound + t + (tLow + randLow * bound shr 32) - (z shr 63) - (bound shr 63)
}
/**
* Inclusive inner, exclusive outer; both inner and outer can be positive or negative.
* @param inner the inner bound, inclusive, can be positive or negative
* @param outer the outer bound, exclusive, can be positive or negative and may be greater than or less than inner
* @return a random long that may be equal to inner and will otherwise be between inner and outer
*/
fun nextLong(inner: Long, outer: Long): Long {
return inner + nextLong(outer - inner)
}
override fun nextDouble(): Double {
return (nextLong() and DOUBLE_MASK) * NORM_53
}
override fun nextFloat(): Float {
return ((nextLong() and FLOAT_MASK) * NORM_24).toFloat()
}
override fun nextBoolean(): Boolean {
return nextLong() < 0L
}
override fun nextBytes(bytes: ByteArray) {
var i = bytes.size
var n = 0
while (i != 0) {
n = Math.min(i, 8)
var bits = nextLong()
while (n-- != 0) {
bytes[--i] = bits.toByte()
bits = bits ushr 8
}
}
}
fun serialize() = state0.toLittle() + state1.toLittle()
/**
* Sets the seed of this generator using one long, running that through LightRNG's algorithm twice to get the state.
* @param seed the number to use as the seed
*/
override fun setSeed(seed: Long) {
var state = seed + -0x61c8864680b583ebL
var z = state
z = (z xor z.ushr(30)) * -0x40a7b892e31b1a47L
z = (z xor z.ushr(27)) * -0x6b2fb644ecceee15L
state0 = z xor z.ushr(31)
state += -0x61c8864680b583ebL
z = state
z = (z xor z.ushr(30)) * -0x40a7b892e31b1a47L
z = (z xor z.ushr(27)) * -0x6b2fb644ecceee15L
state1 = z xor z.ushr(31)
}
/**
* Sets the seed of this generator using two longs, using them without changes unless both are 0 (then it makes the
* state variable corresponding to stateA 1 instead).
* @param stateA the number to use as the first part of the state; this will be 1 instead if both seeds are 0
* @param stateB the number to use as the second part of the state
*/
fun reseed(stateA: Long, stateB: Long) {
state0 = stateA
state1 = stateB
if (stateA or stateB == 0L)
state0 = 1L
}
}*/