All Downloads are FREE. Search and download functionalities are using the official Maven repository.

squidpony.squidmath.Oriole32RNG Maven / Gradle / Ivy

Go to download

SquidLib platform-independent logic and utility code. Please refer to https://github.com/SquidPony/SquidLib .

There is a newer version: 3.0.6
Show newest version
package squidpony.squidmath;

import squidpony.StringKit;

import java.io.Serializable;

/**
 * A modification of Blackman and Vigna's xoroshiro128+ generator using two 32-bit ints of state instead of two 64-bit
 * longs and also incorporating a large-increment counter (Weyl sequence) that is added to the rotated xoroshiro output;
 * this is tied with {@link Lathe32RNG} for the fastest generator on GWT I have found that also passes the full 32TB
 * battery of PractRand's statistical tests. ThrustAlt32RNG is faster in some browsers and also passes tests, but
 * cannot produce all outputs, and its period is too small for serious usage. In statistical testing, xoroshiro always
 * fails some binary matrix rank tests, but smaller-state versions fail other tests as well. The changes Oriole makes
 * apply only to the output of xoroshiro, not its well-tested state transition for the "xoroshiro state" part of this
 * generator, and these changes eliminate all statistical failures on 32TB of tested data, avoiding the failures the
 * small-state variant of xoroshiro suffers on BinaryRank, BCFN, DC6, and FPF. It avoids multiplication, like xoroshiro
 * and much of the xorshift family of generators, and any arithmetic it performs is safe for GWT. Oriole takes advantage
 * of xoroshiro's flaws being mostly confined to its output's lower bits by rotating the output of xoroshiro (the weaker
 * 32-bit-state version) and adding a "Weyl sequence," essentially a large-increment counter that overflows and wraps
 * frequently, to the output. Although the upper bits of xoroshiro are not free of artifacts either, they are harder to
 * find issues with (see
 * this article by PCG-Random's author for
 * more detail). It is unclear if the changes made here would improve the larger-state version, but they probably would
 * help to some extent with at least the binary rank failures. The period is also improved by incorporating the Weyl
 * sequence, up to 0xFFFFFFFFFFFFFFFF00000000 .
 * 
* The name comes from the insectivorous orange songbird called an oriole, which as I have found from the one that * visits my backyard, reacts quickly and is always looking for bugs to remove. It also sounds like "xoro." *
* Original version here for xorshiro128+; this version * uses different constants by the same * author, Sebastiano Vigna. *
* Written in 2016 by David Blackman and Sebastiano Vigna ([email protected]) * Ported and modified in 2018 by Tommy Ettinger * @author Sebastiano Vigna * @author David Blackman * @author Tommy Ettinger (if there's a flaw, use SquidLib's or Sarong's issues and don't bother Vigna or Blackman, it's probably a mistake in SquidLib's implementation) * @see Lathe32RNG A related generator that implements StatefulRandomness and has very similar speed */ public final class Oriole32RNG implements RandomnessSource, Serializable { private static final long serialVersionUID = 1L; private int stateA, stateB, stateC; /** * Creates a new generator seeded using three calls to Math.random(). */ public Oriole32RNG() { setState((int)((Math.random() * 2.0 - 1.0) * 0x80000000), (int)((Math.random() * 2.0 - 1.0) * 0x80000000), (int)((Math.random() * 2.0 - 1.0) * 0x80000000)); } /** * Constructs this Oriole32RNG by dispersing the bits of seed using {@link #setSeed(int)} 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 Oriole32RNG(final int seed) { setSeed(seed); } /** * Constructs this Oriole32RNG by calling {@link #setState(int, int, int)} on stateA and stateB as given but * producing stateC via {@code stateA ^ stateB}; 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 Oriole32RNG(final int stateA, final int stateB) { setState(stateA, stateB, stateA ^ stateB); } /** * Constructs this Oriole32RNG by calling {@link #setState(int, int, int)} 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 * @param stateC the number to use as the counter part of the state (third part) */ public Oriole32RNG(final int stateA, final int stateB, final int stateC) { setState(stateA, stateB, stateC); } @Override public final int next(int bits) { final int s0 = stateA; int s1 = stateB; final int result = s0 + s1; s1 ^= s0; stateA = (s0 << 13 | s0 >>> 19) ^ s1 ^ (s1 << 5); // a, b stateB = (s1 << 28 | s1 >>> 4); // c return (result << 29 | result >>> 3) + (stateC += 0x632BE5AB) >>> (32 - bits); } /** * 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 final int nextInt() { final int s0 = stateA; int s1 = stateB; final int result = s0 + s1; s1 ^= s0; stateA = (s0 << 13 | s0 >>> 19) ^ s1 ^ (s1 << 5); // a, b stateB = (s1 << 28 | s1 >>> 4); // c return (result << 29 | result >>> 3) + (stateC += 0x632BE5AB); } @Override public final long nextLong() { final int s0 = stateA; int s1 = stateB; final int high = s0 + s1; s1 ^= s0; final int s00 = (s0 << 13 | s0 >>> 19) ^ s1 ^ (s1 << 5); // a, b s1 = (s1 << 28 | s1 >>> 4); // c final int low = s00 + s1; s1 ^= s00; stateA = (s00 << 13 | s00 >>> 19) ^ s1 ^ (s1 << 5); // a, b stateB = (s1 << 28 | s1 >>> 4); // c return (long)((high << 29 | high >>> 3) + (stateC + 0x632BE5AB)) << 32 ^ ((low << 29 | low >>> 3) + (stateC += 0xC657CB56)); } /** * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the * copy, both will generate the same sequence of random numbers from the point copy() was called. This just needs to * copy the state so it isn't shared, usually, and produce a new value with the same exact state. * * @return a copy of this RandomnessSource */ @Override public Oriole32RNG copy() { return new Oriole32RNG(stateA, stateB, stateC); } /** * Sets the state of this generator using one int, running it through Zog32RNG's algorithm three times to get * three ints. * @param seed the int to use to assign this generator's state */ public void setSeed(final int seed) { int z = seed + 0xC74EAD55, a = seed ^ z; a ^= a >>> 14; z = (z ^ z >>> 10) * 0xA5CB3; a ^= a >>> 15; stateA = (z ^ z >>> 20) + (a ^= a << 13); z = seed + 0x8E9D5AAA; a ^= a >>> 14; z = (z ^ z >>> 10) * 0xA5CB3; a ^= a >>> 15; stateB = (z ^ z >>> 20) + (a ^ a << 13); if((stateA | stateB) == 0) stateA = 1; z = seed - 0xC74EAD55; a ^= a >>> 14; z = (z ^ z >>> 10) * 0xA5CB3; a ^= a >>> 15; stateC = (z ^ z >>> 20) + (a ^ a << 13); } public int getStateA() { return stateA; } public void setStateA(int stateA) { this.stateA = (stateA | stateB) == 0 ? 1 : stateA; } public int getStateB() { return stateB; } public void setStateB(int stateB) { this.stateB = stateB; if((stateB | stateA) == 0) stateA = 1; } public int getStateC() { return stateC; } public void setStateC(int stateC) { this.stateC = stateC; } /** * Sets the current internal state of this Oriole32RNG with three ints, where stateA and stateB can each be any int * unless they are both 0, and stateC can be any int without restrictions. * @param stateA any int except 0 (0 will be treated as 1 instead) * @param stateB any int */ public void setState(int stateA, int stateB, int stateC) { this.stateA = (stateA | stateB) == 0 ? 1 : stateA; this.stateB = stateB; this.stateC = stateC; } @Override public String toString() { return "Oriole32RNG with stateA 0x" + StringKit.hex(stateA) + ", stateB 0x" + StringKit.hex(stateB) + ", and stateC 0x" + StringKit.hex(stateC); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Oriole32RNG oriole32RNG = (Oriole32RNG) o; return stateA == oriole32RNG.stateA && stateB == oriole32RNG.stateB && stateC == oriole32RNG.stateC; } @Override public int hashCode() { return 31 * stateA + stateB; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy