Everyone’s first program:
import java.util.concurrent.atomic.AtomicLong;
/**
* <b>Coding comments</b>
* <p>
* Threading. All methods are reentrant. Technically a given instance is
* not thread safe. From a practical standpoint, calling from multiple
* threads will simply make the instance non-deterministic. Heavy access
* from multiple threads is undesirable as each call will cause cache
* line invalidations in all other actively accessing threads (assuming
* on different cores). Specifically it's possible for the sequence to
* appear to rewind some number of positions.
*/
public class Dice
{
private static AtomicLong mix = new AtomicLong();
private int seed;
// these are proven reasonable number from L'Ecuyer
private static final int RNG_M = 0xac549d55;
private static final int RNG_A = 54321;
public Dice(int seed)
{
this.seed = seed;
}
public Dice()
{
this((int)(mix.getAndDecrement() ^ System.nanoTime()));
}
/**
* Simple 32-bit LCG. Roughly the top 14-16 bits are
* reasonable.
*/
private final int rng()
{
int r = seed;
r *= RNG_M;
r += RNG_A;
seed = r;
return seed;
}
/**
* almost uniform random on [0,0xFFFF]
*/
private final int rng16()
{
return rng() >>> 16;
}
/**
* almost uniform random on [-,]
*/
@SuppressWarnings("unused")
private final int rng16s()
{
return rng() >> 16;
}
// 32-bit random number
private final int rng32()
{
int r;
r = (rng() >>> 16);
r |= (rng() & 0xFFFF0000);
return r;
}
/**
* Generates a (nearly) uniform random number on the
* range [0, range).
* <p>
*/
private final int rng(int range)
{
return ((rng()>>>15) * range) >>> 17;
}
/**
*
*/
public final void setSeed(int seed)
{
this.seed = seed;
}
public final int getSeed()
{
return seed;
}
/**
* Simulates flipping 'n' coins.
* <p>
* The legal range of 'n' is [1, 16]
*/
public final int flip16(int n)
{
return Integer.bitCount(rng() >>> (32-n));
}
/**
* Simulates flipping 'n' coins.
* <p>
* The legal range of 'n' is [1, 32].
*/
public final int flip32(int n)
{
return Integer.bitCount(rng32() >>> (32-n));
}
/**
* Simulates flipping 16 coins.
* <p>
* Returns a random number on the range [0, 16].
* <p>
* @see #flip16(int)
* @see #flip32()
*/
public final int flip16()
{
return Integer.bitCount(rng16());
}
/**
* Simulates flipping 32 coins.
* <p>
* Returns a random number on the range [0, 32]
*/
public final int flip32()
{
return Integer.bitCount(rng32());
}
/** Flips a coin. Result is 1 or 2. */
public final int d2()
{
return 1 + (rng() >>> 31);
}
/** Simulates the sum of <i>n</i> coin tosses. */
public final int d2(int n)
{
int r = n;
while (n >= 32) {
r += flip32();
n -= 32;
}
if (n >= 16) {
r += flip16();
n -= 16;
}
if (n != 0)
r += flip16(n);
return r;
}
/** Simulates a roll of a four sided die. */
public final int d4()
{
return 1 + (rng() >>> 30);
}
/** Simulates the sum of <i>n</i> four sided dice rolls.*/
public final int d4(int n)
{
int r = n;
for(int i=0; i<n; i++)
r += (rng() >>> 30);
return r;
}
/** Simulates a roll of a six sided die. */
public final int d6()
{
// 6 = 3*2 = (2+1)*2
int r = rng16();
r = ((r<<1)+r) >>> 15;
return r+1;
}
/** Simulates the sum of <i>n</i> six sided dice rolls.*/
public final int d6(int n)
{
int r = 0;
for(int i=0; i<n; i++)
r += d6();
return r;
}
/** Simulates a roll of an eight sided die. */
public final int d8()
{
return 1 + (rng() >>> 29);
}
/** Simulates the sum of <i>n</i> eight sided dice rolls.*/
public final int d8(int n)
{
int r = n;
for(int i=0; i<n; i++)
r += (rng() >>> 29);
return r;
}
/** Simulates a roll of a ten sided die. */
public final int d10()
{
// 10 = 5*2 = (4+1)*2
int r = rng16();
r = ((r<<2)+r) >>> 15;
return r+1;
}
/** Simulates the sum of <i>n</i> ten sided dice rolls.*/
public final int d10(int n)
{
int r = 0;
for(int i=0; i<n; i++)
r += d10();
return r;
}
/** Simulates a roll of a twelve sided die. */
public final int d12()
{
// 12 = 3*4 = (2+1)*4
int r = rng16();
r = ((r<<1)+r) >>> 14;
return r+1;
}
/** Simulates the sum of <i>n</i> twelve sided dice rolls.*/
public final int d12(int n)
{
int r = 0;
for(int i=0; i<n; i++)
r += d12();
return r;
}
/** Simulates a roll of a twenty sided die. */
public final int d20()
{
// 20 = 5*4 = (4+1)*4
int r = rng16();
r = ((r<<2)+r) >>> 14;
return r+1;
}
/** Simulates the sum of <i>n</i> twenty sided dice rolls.*/
public final int d20(int n)
{
int r = 0;
for(int i=0; i<n; i++)
r += d20();
return r;
}
/** Simulates a roll of a one-hundred sided die. */
public final int d100()
{
// 100 = 25*4 = (3*8+1)*4
int r = rng() >>> 14;
int t = (r << 1)+r;
r = ((t<<3)+r) >>> 16;
return r+1;
}
/** Simulates the sum of <i>n</i> one-hundred sided dice rolls.*/
public final int d100(int n)
{
int r = 0;
for(int i=0; i<n; i++)
r += d100();
return r;
}
/**
* Returns a random number on [0, 0xFFFF] with a
* triangular distribution.
*/
public final int triangle()
{
int r0 = rng16();
int r1 = rng16();
return (r0+r1+1)>>1;
}
/**
* Returns a random number on [0, range) with a
* triangular distribution.
*/
public final int triangle(int range)
{
return (triangle() * range) >>> 16;
}
/**
* Returns a random number with a triangle distribution.
* <p>
* [0, a+b)
* <p>
* a 'steps' of linear increase/decreasing on the edges
*/
public final int triangle(int a, int b)
{
// complete comments
// isn't it really a+b-1
a = rng(a);
b = rng(b);
return a+b;
}
}