#define RNG_MULT 0x5DEECE66DL #define RNG_ADDEND 0xBL #define RNG_MASK (1L << 48) - 1 #define RNG_UNIT 0x1.0p-53 // 1.0 / (1L << 53) ulong rng_rseed() { return (((sys.rng_uniq *= 181783497276652981L) ^ tmr_ntime()) ^ RNG_MULT) & RNG_MASK; } ulong rng_sseed(ulong seed) { return (seed ^ RNG_MULT) & RNG_MASK; } uint rng_gen(ulong *rand, int bits) { *rand = ((*rand) * RNG_MULT + RNG_ADDEND) & RNG_MASK; return (uint)((*rand) >> (48 - bits)); } uint rng_uint(ulong *rand) { return rng_gen(rand, 32); } int rng_zrange(ulong *rand, int bound) { sys_assert(bound > 0); int r = rng_gen(rand, 31); int m = bound - 1; if((bound & m) == 0) // ^2 r = (int)((bound * (long)r) >> 31); else for(int u = r; u - (r = u % bound) + m < 0; u = rng_gen(rand, 31)); return r; } uint rng_urange(ulong *rand, uint bound) { sys_assert(bound); uint r = rng_gen(rand, 32); uint m = bound - 1; if((bound & m) == 0) // ^2 r = (uint)((bound * (ulong)r) >> 31); else for(uint u = r; u - (r = u % bound) + m < 0; u = rng_gen(rand, 32)); return r; } ulong rng_ulong(ulong *rand) { return ((ulong)(rng_gen(rand, 32)) << 32) | (ulong)rng_gen(rand, 32); } byte rng_bool(ulong *rand) { return (byte)rng_gen(rand, 1); } float rng_float(ulong *rand) { return rng_gen(rand, 24) / ((float)(1 << 24)); } double rng_double(ulong *rand) { return (((long)(rng_gen(rand, 26)) << 27) + rng_gen(rand, 27)) * RNG_UNIT; } void rng_gauss(ulong *rand, double *n1, double *n2) { double v1, v2, s; do { v1 = 2.0 * rng_double(rand) - 1.0; // between -1 and 1 v2 = 2.0 * rng_double(rand) - 1.0; // between -1 and 1 s = v1 * v1 + v2 * v2; } while (s >= 1.0 || s == 0.0); double mul = sqrt(-2.0 * log(s)/s); *n1 = v1 * mul; *n2 = v2 * mul; } int rng_excl(ulong *rand, int min, int max) { return min + rng_zrange(rand, max - min); } int rng_ch_offset(ulong *rand) { return 8 + rng_gen(rand, 4); } int rng_roll(ulong *rand, int range) { return 1 + rng_zrange(rand, range); } int rng_roll_bonus(ulong *rand, int range, int bonus) { return 1 + rng_zrange(rand, range) + rng_zrange(rand, bonus + 1); } int rng_range(ulong *rand, int min, int max) { return min + rng_zrange(rand, max + 1 - min); } int rng_range_bonus(ulong *rand, int min, int max, int bonus) { return (min + rng_zrange(rand, max + 1 - min)) + rng_zrange(rand, bonus + 1); } int rng_range_checked(ulong *rand, int min, int max) { return min >= max ? min : (rng_zrange(rand, max + 1 - min) + min); } float rng_frange(ulong *rand, float min, float max) { return min >= max ? min : (rng_float(rand) * (max - min) + min); } double rng_drange(ulong *rand, double min, double max) { return min >= max ? min : (rng_double(rand) * (max - min) + min); } byte rng_chance(ulong *rand, int chance) { return !rng_zrange(rand, chance); } byte rng_rarity(ulong *rand, int chance) { return rng_zrange(rand, chance) != 0; } void *rng_select(ulong *rand, void *a, void *b, int chance) { return rng_zrange(rand, chance) ? a : b; } int rng_iselect(ulong *rand, int a, int b, int chance) { return rng_zrange(rand, chance) ? a : b; } byte rng_percent(ulong *rand, float chance) { return rng_float(rand) < chance / 100.0f; } void *rng_pselect(ulong *rand, void *a, void *b, float chance) { return rng_float(rand) < chance / 100.0f ? b : a; } void *rng_rselect(ulong *rand, void *a, void *b) { return rng_gen(rand, 1) != 0 ? b : a; } void *rng_pick(ulong *rand, void **obj, uint size) { return obj[rng_zrange(rand, size)]; } int rng_ipick(ulong *rand, int *obj, uint size) { return obj[rng_zrange(rand, size)]; } void *rng_weight(ulong *rand, void *a, void *b, int ca, int cb) { return rng_zrange(rand, ca + cb) >= ca ? b : a; } void *rng_fselect(ulong *rand, void *a, void *b, float chance) { return rng_float(rand) < chance ? b : a; }