83 lines
2.2 KiB
JavaScript
83 lines
2.2 KiB
JavaScript
import Long from "../../../../../libraries/long.js";
|
|
|
|
export default class Random {
|
|
|
|
static instances = 0;
|
|
|
|
constructor(seed = Date.now() % 1000000000 ^ Random.instances++ * 1000) {
|
|
this.multiplier = Long.fromString("25214903917");
|
|
this.mask = Long.fromInt(1).shiftLeft(48).subtract(1);
|
|
this.addend = Long.fromInt(0xB);
|
|
this.doubleUnit = 1.1102230246251565E-16;
|
|
this.maxInt = Long.fromInt(0x7fffffff);
|
|
this.intMask = Long.fromInt(0x80000000);
|
|
|
|
this.setSeed(seed);
|
|
}
|
|
|
|
nextFloat() {
|
|
return this.next(24).toNumber() / (1 << 24);
|
|
}
|
|
|
|
nextDouble() {
|
|
return this.next(26).shiftLeft(27).add(this.next(27)).toNumber() * this.doubleUnit;
|
|
}
|
|
|
|
nextInt(max = -1) {
|
|
if (max === -1) {
|
|
return this.next(32).toNumber();
|
|
}
|
|
|
|
let r = this.next(31);
|
|
let m = max - 1;
|
|
if ((max & m) === 0) // i.e., bound is a power of 2
|
|
r = Long.fromInt(max).multiply(r).shiftRightUnsigned(31).toNumber();
|
|
else {
|
|
r = r.toNumber();
|
|
for (let u = r;
|
|
u - (r = u % max) + m < 0;
|
|
u = this.next(31).toNumber())
|
|
;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
nextLong() {
|
|
return this.next(32).shiftLeft(32).add(this.next(32));
|
|
}
|
|
|
|
next(bits) {
|
|
let oldSeed;
|
|
let nextSeed;
|
|
do {
|
|
oldSeed = this.seed;
|
|
nextSeed = oldSeed.multiply(this.multiplier).add(this.addend).and(this.mask);
|
|
} while (!this._compareAndSet(oldSeed, nextSeed));
|
|
|
|
let num = nextSeed.shiftRight(48 - bits);
|
|
return num.greaterThan(this.maxInt) ? num.or(this.intMask) : num; // Cast to integer
|
|
}
|
|
|
|
_compareAndSet(expect, update) {
|
|
if (!this.seed.equals(expect)) {
|
|
return false;
|
|
}
|
|
|
|
this.seed = update;
|
|
return true;
|
|
}
|
|
|
|
setSeed(n) {
|
|
let long;
|
|
|
|
if (typeof n === "number") {
|
|
long = Long.fromInt(n);
|
|
} else if (n instanceof Long) {
|
|
long = n;
|
|
} else {
|
|
long = Long.fromString(n);
|
|
}
|
|
|
|
this.seed = long.xor(this.multiplier).and(this.mask);
|
|
}
|
|
} |