Updated random interface.

This commit is contained in:
Christoffer Lerno
2023-08-26 12:58:57 +02:00
parent 6ebd437a5f
commit bea9ac010c
9 changed files with 849 additions and 277 deletions

View File

@@ -2,23 +2,16 @@ module std::math;
struct Random
{
RandomInterface fns;
void* state;
RandomInterface* fns;
}
fn uint any.next_random(void*, int bits) @interface;
fn void any.next_random_bytes(void*, char[] buffer) @interface;
fn void any.set_random_seed(void*, char[] seed) @interface;
def RandomSeedFn = fn void(Random*, char[] seed);
def RandomNextBytesFn = fn void(Random*, char[] buffer);
def RandomNextFn = fn uint(Random*, int bits);
struct RandomInterface
{
RandomSeedFn seed_fn;
RandomNextBytesFn next_bytes_fn;
RandomNextFn next_fn;
}
/**
@@ -28,66 +21,65 @@ struct RandomInterface
fn void Random.next_bytes(&random, char[] buffer)
{
if (!buffer.len) return;
if (RandomNextBytesFn func = random.fns.next_bytes_fn)
{
func(random, buffer);
return;
}
if (RandomNextFn func = random.fns.next_fn)
{
usz current = 0;
while (current < buffer.len)
{
char[4] res = bitcast(func(random, 32), char[4]);
foreach (c : res)
{
buffer[current++] = c;
if (current == buffer.len) return;
}
}
return;
}
unreachable("Invalid Random type.");
random.fns.next_bytes_fn(random, buffer);
}
/**
* @param [&inout] random
* @require bits >= 0 && bits <= 32
* @param [&inout] self
**/
fn uint Random.next(&random, int bits)
fn char Random.next_byte(&self)
{
if (bits == 0) return 0;
if (RandomNextFn func = random.fns.next_fn) return func(random, bits);
int bytes = (bits + 7) / 8;
char[4] buffer;
char[] b = buffer[:bytes];
assert(random.fns.next_bytes_fn, "Invalid Random");
random.fns.next_bytes_fn(random, b) @inline;
uint next = 0;
foreach (char c : b)
{
next = next << 8 + c;
}
if (bits < 32) next >>= bytes * 8 - bits;
return next;
char result @noinit;
self.next_bytes(((char*)&result)[:1]);
return result;
}
/**
* @param [&inout] random
* @param [&inout] self
**/
fn ulong Random.next_long(&random)
fn uint Random.next_short(&self)
{
char[8] buffer;
random.next_bytes(&buffer);
return bitcast(buffer, ulong);
ushort result @noinit;
self.next_bytes(((char*)&result)[:2]);
return result;
}
/**
* @param [&inout] random
* @param [&inout] self
**/
fn void Random.set_seed(&random, long seed)
fn uint Random.next_int(&self)
{
random.fns.seed_fn(random, &&bitcast(seed, char[8])) @inline;
uint result @noinit;
self.next_bytes(((char*)&result)[:4]);
return result;
}
/**
* @param [&inout] self
**/
fn ulong Random.next_long(&self)
{
ulong result @noinit;
self.next_bytes(((char*)&result)[:8]);
return result;
}
/**
* @param [&inout] self
**/
fn uint128 Random.next_uint128(&self)
{
uint128 result @noinit;
self.next_bytes(((char*)&result)[:16]);
return result;
}
/**
* @param [&inout] self
**/
fn void Random.set_seed(&self, long seed)
{
self.fns.seed_fn(self, &&bitcast(seed, char[8])) @inline;
}
/**
@@ -100,24 +92,42 @@ fn void Random.set_seeds(&random, char[] seed)
}
/**
* @param [&inout] random
* @param [&inout] self
**/
fn bool Random.next_bool(&random)
fn bool Random.next_bool(&self)
{
return random.next(1) != 0;
return self.next_byte() & 1 == 0;
}
fn float Random.next_float(&r)
fn float Random.next_float(&self)
{
return r.next(24) / (float)(1 << 24);
uint val = self.next_int() & (1 << 24 - 1);
return val / (float)(1 << 24);
}
fn double Random.next_double(&r)
fn double Random.next_double(&self)
{
return (((long)(r.next(26)) << 27) + r.next(27)) * 0x1.0p-53;
ulong val = self.next_long() & (1UL << 53 - 1);
return val * 0x1.0p-53;
}
fn uint Random.next_int(&r)
macro @random_value_to_bytes(#function, char[] bytes)
{
return r.next(32) @inline;
}
var $byte_size = $sizeof(#function());
usz len = bytes.len;
// Same size or smaller? Then just copy.
while (len > 0)
{
var value = #function();
if (len <= $byte_size)
{
bytes[..] = ((char*)&value)[:len];
return;
}
bytes[:$byte_size] = ((char*)&value)[:$byte_size];
len -= $byte_size;
bytes = bytes[$byte_size..];
}
unreachable();
}

View File

@@ -14,16 +14,45 @@ const MUL_LCG16 @local = 0x915d; // TODO: Find good constant
// -------------------------------- Lcg128_64 --------------------------------
def Lcg128_64 = distinct uint128;
fn void Lcg128_64.seed(&lcg, char[16] seed)
struct Lcg128Random
{
*lcg = bitcast(seed, Lcg128_64);
inline Random random;
Lcg128RandomState state;
}
fn ulong Lcg128_64.next(&lcg)
def Lcg128RandomState = distinct uint128;
const RandomInterface LCG_128_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Lcg128Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Lcg128Random.next_bytes,
};
fn void Lcg128Random.init(&self)
{
uint128* s = (uint128*)lcg;
self.random.fns = &LCG_128_RANDOM_INTERFACE;
}
fn void Lcg128Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(uint128, input));
}
/**
* @require bytes.len > 0
**/
fn void Lcg128Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_long, bytes);
}
fn void Lcg128RandomState.set_seed(&self, uint128 seed) @inline
{
*self = (Lcg128RandomState)seed;
}
fn ulong Lcg128RandomState.next_long(&self)
{
uint128* s = (uint128*)self;
ulong result = (ulong)(*s >> 64);
*s = *s * MUL_LCG128 + ODD_PHI128;
return result;
@@ -32,16 +61,45 @@ fn ulong Lcg128_64.next(&lcg)
// -------------------------------- Lcg64_32 --------------------------------
def Lcg64_32 = distinct ulong;
fn void Lcg64_32.seed(&lcg, char[8] seed)
struct Lcg64Random
{
*lcg = bitcast(seed, Lcg64_32);
inline Random random;
Lcg64RandomState state;
}
fn uint Lcg64_32.next(&lcg)
def Lcg64RandomState = distinct ulong;
const RandomInterface LCG_64_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Lcg64Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Lcg64Random.next_bytes,
};
fn void Lcg64Random.init(&self)
{
ulong* s = (ulong*)lcg;
self.random.fns = &LCG_64_RANDOM_INTERFACE;
}
fn void Lcg64Random.set_seed(&self, char[] seed)
{
self.state.set_seed(random::make_seed(ulong, seed));
}
/**
* @require bytes.len > 0
**/
fn void Lcg64Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_int, bytes);
}
fn void Lcg64RandomState.set_seed(&self, ulong seed)
{
*self = (Lcg64RandomState)seed;
}
fn uint Lcg64RandomState.next_int(&self)
{
ulong* s = (ulong*)self;
uint result = (uint)(*s >> 32);
*s = *s * MUL_LCG64 + ODD_PHI64;
return result;
@@ -50,16 +108,16 @@ fn uint Lcg64_32.next(&lcg)
// -------------------------------- Lcg32_16 --------------------------------
def Lcg32_16 = distinct uint;
def Lcg32RandomState = distinct uint;
fn void Lcg32_16.seed(&lcg, char[4] seed)
fn void Lcg32RandomState.set_seed(&self, uint seed)
{
*lcg = bitcast(seed, Lcg32_16);
*self = (Lcg32RandomState)seed;
}
fn ushort Lcg32_16.next(&lcg)
fn ushort Lcg32RandomState.next_short(&self)
{
uint* s = (uint*)lcg;
uint* s = (uint*)self;
ushort result = (ushort)(*s >> 16);
*s = *s * MUL_LCG32 + ODD_PHI32;
return result;
@@ -68,16 +126,16 @@ fn ushort Lcg32_16.next(&lcg)
// -------------------------------- Lcg16_8 --------------------------------
def Lcg16_8 = distinct ushort;
def Lcg16RandomState = distinct ushort;
fn void Lcg16_8.seed(&lcg, char[2] seed)
fn void Lcg16RandomState.set_seed(&self, ushort seed)
{
*lcg = bitcast(seed, Lcg16_8);
*self = (Lcg16RandomState)seed;
}
fn char Lcg16_8.next(&lcg)
fn char Lcg16RandomState.next_byte(&self)
{
ushort* s = (ushort*)lcg;
ushort* s = (ushort*)self;
char result = (char)(*s >> 8);
*s = *s * MUL_LCG16 + ODD_PHI16;
return result;

View File

@@ -7,70 +7,130 @@ const MUL_MCG16 @local = 0x93d5; // TODO: Find good constant
// -------------------------------- Mcg128_64 --------------------------------
def Mcg128_64 = distinct uint128;
fn void Mcg128_64.seed(&mcg, char[16] seed)
struct Mcg128Random
{
*mcg = bitcast(seed, Mcg128_64) | 1;
inline Random random;
Mcg128RandomState state;
}
fn ulong Mcg128_64.next(&mcg)
def Mcg128RandomState = distinct uint128;
const RandomInterface MCG_128_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Mcg128Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Mcg128Random.next_bytes,
};
fn void Mcg128Random.init(&self)
{
uint128* s = (uint128*)mcg;
self.random.fns = &MCG_64_RANDOM_INTERFACE;
}
fn void Mcg128Random.set_seed(&self, char[] seed)
{
self.state.set_seed(random::make_seed(uint128, seed));
}
/**
* @require bytes.len > 0
**/
fn void Mcg128Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_long, bytes);
}
fn void Mcg128RandomState.set_seed(&self, uint128 seed)
{
*self = (Mcg128RandomState)seed | 1;
}
fn ulong Mcg128RandomState.next_long(&self)
{
uint128* s = (uint128*)self;
ulong result = (ulong)(*s >> 64);
*s *= MUL_MCG128;
return result;
}
// -------------------------------- Mcg64_32 --------------------------------
def Mcg64_32 = distinct ulong;
fn void Mcg64_32.seed(&mcg, char[8] seed)
// -------------------------------- Mcg64RandomState --------------------------------
struct Mcg64Random
{
*mcg = bitcast(seed, Mcg64_32) | 1;
inline Random random;
Mcg64RandomState state;
}
fn uint Mcg64_32.next(&mcg)
const RandomInterface MCG_64_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Mcg64Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Mcg64Random.next_bytes,
};
def Mcg64RandomState = distinct ulong;
fn void Mcg64Random.init(&self)
{
ulong* s = (ulong*)mcg;
self.random.fns = &MCG_64_RANDOM_INTERFACE;
}
fn void Mcg64Random.set_seed(&self, char[] seed)
{
self.state.set_seed(random::make_seed(ulong, seed));
}
/**
* @require bytes.len > 0
**/
fn void Mcg64Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_int, bytes);
}
fn void Mcg64RandomState.set_seed(&self, ulong seed)
{
*self = (Mcg64RandomState)self | 1;
}
fn uint Mcg64RandomState.next_int(&self)
{
ulong* s = (ulong*)self;
uint result = (uint)(*s >> 32);
*s *= MUL_MCG64;
return result;
}
// -------------------------------- Mcg32_16 --------------------------------
// -------------------------------- Mcg32RandomState --------------------------------
def Mcg32_16 = distinct uint;
def Mcg32RandomState = distinct uint;
fn void Mcg32_16.seed(&mcg, char[4] seed)
fn void Mcg32RandomState.set_seed(&self, uint seed)
{
*mcg = bitcast(seed, Mcg32_16) | 1;
*self = (Mcg32RandomState)seed | 1;
}
fn ushort Mcg32_16.next(&mcg)
fn ushort Mcg32RandomState.next_short(&self)
{
uint* s = (uint*)mcg;
uint* s = (uint*)self;
ushort result = (ushort)(*s >> 16);
*s *= MUL_MCG32;
return result;
}
// -------------------------------- Mcg16_8 --------------------------------
// -------------------------------- Mcg16RandomState --------------------------------
def Mcg16_8 = distinct ushort;
def Mcg16RandomState = distinct ushort;
fn void Mcg16_8.seed(&mcg, char[2] seed)
fn void Mcg16RandomState.set_seed(&self, ushort seed)
{
*mcg = bitcast(seed, Mcg16_8) | 1;
*self = (Mcg16RandomState)seed | 1;
}
fn char Mcg16_8.next(&mcg)
fn char Mcg16RandomState.next_byte(&self)
{
ushort* s = (ushort*)mcg;
ushort* s = (ushort*)self;
char result = (char)(*s >> 8);
*s *= MUL_MCG16;
return result;

View File

@@ -10,27 +10,57 @@ const ODD_PHI8 @local = 0x9f;
// -------------------------------- Msws128 --------------------------------
struct Msws128 {
struct Msws128Random
{
inline Random random;
Msws128RandomState state;
}
struct Msws128RandomState
{
uint128 state0, state1;
uint128 weyl0, weyl1;
}
fn void Msws128.seed(&msws, char[16 * 4] seed)
const RandomInterface MSWS_128_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Msws128Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Msws128Random.next_bytes,
};
fn void Msws128Random.init(&self)
{
*msws = bitcast(seed, Msws128);
self.random.fns = &MSWS_128_RANDOM_INTERFACE;
}
fn uint128 Msws128.next(&msws)
fn void Msws128Random.set_seed(&self, char[] input)
{
uint128 s0 = msws.state0;
msws.state0 = msws.state0 * msws.state0 + msws.weyl0;
msws.state0 = msws.state0.rotr(64);
msws.weyl0 += ODD_PHI128;
self.state.set_seed(random::make_seed(uint128[4], input));
}
msws.state1 = msws.state1 * msws.state1 + msws.weyl1;
uint128 s1 = msws.state1;
msws.state1 = msws.state1.rotr(64);
msws.weyl1 -= ODD_PHI128;
/**
* @require bytes.len > 0
**/
fn void Msws128Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_int128, bytes);
}
fn void Msws128RandomState.set_seed(&self, uint128[4] seed)
{
*self = bitcast(seed, Msws128RandomState);
}
fn uint128 Msws128RandomState.next_int128(&self)
{
uint128 s0 = self.state0;
self.state0 = self.state0 * self.state0 + self.weyl0;
self.state0 = self.state0.rotr(64);
self.weyl0 += ODD_PHI128;
self.state1 = self.state1 * self.state1 + self.weyl1;
uint128 s1 = self.state1;
self.state1 = self.state1.rotr(64);
self.weyl1 -= ODD_PHI128;
return s0 + s1;
}
@@ -38,27 +68,57 @@ fn uint128 Msws128.next(&msws)
// -------------------------------- Msws64 --------------------------------
struct Msws64 {
struct Msws64Random
{
inline Random random;
Msws64RandomState state;
}
struct Msws64RandomState
{
ulong state0, state1;
ulong weyl0, weyl1;
}
fn void Msws64.seed(&msws, char[8 * 4] seed)
const RandomInterface MSWS_64_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Msws64Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Msws64Random.next_bytes,
};
fn void Msws64Random.init(&self)
{
*msws = bitcast(seed, Msws64);
self.random.fns = &MSWS_64_RANDOM_INTERFACE;
}
fn ulong Msws64.next(&msws)
fn void Msws64Random.set_seed(&self, char[] input)
{
ulong s0 = msws.state0;
msws.state0 = msws.state0 * msws.state0 + msws.weyl0;
msws.state0 = msws.state0.rotr(32);
msws.weyl0 += ODD_PHI64;
self.state.set_seed(random::make_seed(ulong[4], input));
}
msws.state1 = msws.state1 * msws.state1 + msws.weyl1;
ulong s1 = msws.state1;
msws.state1 = msws.state1.rotr(32);
msws.weyl1 -= ODD_PHI64;
/**
* @require bytes.len > 0
**/
fn void Msws64Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_long, bytes);
}
fn void Msws64RandomState.set_seed(&self, ulong[4] seed)
{
*self = bitcast(seed, Msws64RandomState);
}
fn ulong Msws64RandomState.next_long(&self)
{
ulong s0 = self.state0;
self.state0 = self.state0 * self.state0 + self.weyl0;
self.state0 = self.state0.rotr(32);
self.weyl0 += ODD_PHI64;
self.state1 = self.state1 * self.state1 + self.weyl1;
ulong s1 = self.state1;
self.state1 = self.state1.rotr(32);
self.weyl1 -= ODD_PHI64;
return s0 + s1;
}
@@ -66,27 +126,57 @@ fn ulong Msws64.next(&msws)
// -------------------------------- Msws32 --------------------------------
struct Msws32 {
struct Msws32Random
{
inline Random random;
Msws32RandomState state;
}
struct Msws32RandomState
{
uint state0, state1;
uint weyl0, weyl1;
}
fn void Msws32.seed(&msws, char[4 * 4] seed)
const RandomInterface MSWS_32_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Msws32Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Msws32Random.next_bytes,
};
fn void Msws32Random.init(&self)
{
*msws = bitcast(seed, Msws32);
self.random.fns = &MSWS_32_RANDOM_INTERFACE;
}
fn uint Msws32.next(&msws)
fn void Msws32Random.set_seed(&self, char[] input)
{
uint s0 = msws.state0;
msws.state0 = msws.state0 * msws.state0 + msws.weyl0;
msws.state0 = msws.state0.rotr(16);
msws.weyl0 += ODD_PHI32;
self.state.set_seed(random::make_seed(uint[4], input));
}
msws.state1 = msws.state1 * msws.state1 + msws.weyl1;
uint s1 = msws.state1;
msws.state1 = msws.state1.rotr(16);
msws.weyl1 -= ODD_PHI32;
/**
* @require bytes.len > 0
**/
fn void Msws32Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_int, bytes);
}
fn void Msws32RandomState.set_seed(&self, uint[4] seed)
{
*self = bitcast(seed, Msws32RandomState);
}
fn uint Msws32RandomState.next_int(&self)
{
uint s0 = self.state0;
self.state0 = self.state0 * self.state0 + self.weyl0;
self.state0 = self.state0.rotr(16);
self.weyl0 += ODD_PHI32;
self.state1 = self.state1 * self.state1 + self.weyl1;
uint s1 = self.state1;
self.state1 = self.state1.rotr(16);
self.weyl1 -= ODD_PHI32;
return s0 + s1;
}
@@ -94,27 +184,58 @@ fn uint Msws32.next(&msws)
// -------------------------------- Msws16 --------------------------------
struct Msws16 {
struct Msws16Random
{
inline Random random;
Msws16RandomState state;
}
struct Msws16RandomState
{
ushort state0, state1;
ushort weyl0, weyl1;
}
fn void Msws16.seed(&msws, char[2 * 4] seed)
const RandomInterface MSWS_16_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Msws16Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Msws16Random.next_bytes,
};
fn void Msws16Random.init(&self)
{
*msws = bitcast(seed, Msws16);
self.random.fns = &MSWS_16_RANDOM_INTERFACE;
}
fn ushort Msws16.next(&msws)
fn void Msws16Random.set_seed(&self, char[] input)
{
ushort s0 = msws.state0;
msws.state0 = msws.state0 * msws.state0 + msws.weyl0;
msws.state0 = msws.state0.rotr(8);
msws.weyl0 += ODD_PHI16;
self.state.set_seed(random::make_seed(ushort[4], input));
}
msws.state1 = msws.state1 * msws.state1 + msws.weyl1;
ushort s1 = msws.state1;
msws.state1 = msws.state1.rotr(8);
msws.weyl1 -= ODD_PHI16;
/**
* @require bytes.len > 0
**/
fn void Msws16Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_short, bytes);
}
fn void Msws16RandomState.set_seed(&self, ushort[4] seed)
{
*self = bitcast(seed, Msws16RandomState);
}
fn ushort Msws16RandomState.next_short(&self)
{
ushort s0 = self.state0;
self.state0 = self.state0 * self.state0 + self.weyl0;
self.state0 = self.state0.rotr(8);
self.weyl0 += ODD_PHI16;
self.state1 = self.state1 * self.state1 + self.weyl1;
ushort s1 = self.state1;
self.state1 = self.state1.rotr(8);
self.weyl1 -= ODD_PHI16;
return s0 + s1;
}
@@ -122,27 +243,57 @@ fn ushort Msws16.next(&msws)
// -------------------------------- Msws8 --------------------------------
struct Msws8 {
struct Msws8Random
{
inline Random random;
Msws8RandomState state;
}
struct Msws8RandomState
{
char state0, state1;
char weyl0, weyl1;
}
fn void Msws8.seed(&msws, char[1 * 4] seed)
const RandomInterface MSWS_8_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Msws8Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Msws8Random.next_bytes,
};
fn void Msws8Random.init(&self)
{
*msws = bitcast(seed, Msws8);
self.random.fns = &MSWS_8_RANDOM_INTERFACE;
}
fn char Msws8.next(&msws)
fn void Msws8Random.set_seed(&self, char[] input)
{
char s0 = msws.state0;
msws.state0 = msws.state0 * msws.state0 + msws.weyl0;
msws.state0 = msws.state0.rotr(4);
msws.weyl0 += ODD_PHI8;
self.state.set_seed(random::make_seed(char[4], input));
}
msws.state1 = msws.state1 * msws.state1 + msws.weyl1;
char s1 = msws.state1;
msws.state1 = msws.state1.rotr(4);
msws.weyl1 -= ODD_PHI8;
/**
* @require bytes.len > 0
**/
fn void Msws8Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_byte, bytes);
}
fn void Msws8RandomState.set_seed(&msws, char[4] seed)
{
*msws = bitcast(seed, Msws8RandomState);
}
fn char Msws8RandomState.next_byte(&self)
{
char s0 = self.state0;
self.state0 = self.state0 * self.state0 + self.weyl0;
self.state0 = self.state0.rotr(4);
self.weyl0 += ODD_PHI8;
self.state1 = self.state1 * self.state1 + self.weyl1;
char s1 = self.state1;
self.state1 = self.state1.rotr(4);
self.weyl1 -= ODD_PHI8;
return s0 + s1;
}

View File

@@ -14,17 +14,46 @@ const MUL_LCG16 @local = 0x915d; // TODO: Find good constant
// -------------------------------- Pcg128_64 --------------------------------
def Pcg128_64 = distinct uint128;
fn void Pcg128_64.seed(&pcg, char[16] seed)
struct Pcg128Random
{
*pcg = bitcast(seed, Pcg128_64);
inline Random random;
Pcg128RandomState state;
}
fn ulong Pcg128_64.next(&pcg)
def Pcg128RandomState = distinct uint128;
const RandomInterface PCG_128_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Pcg128Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Pcg128Random.next_bytes,
};
fn void Pcg128Random.init(&self)
{
self.random.fns = &PCG_128_RANDOM_INTERFACE;
}
fn void Pcg128Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(uint128, input));
}
/**
* @require bytes.len > 0
**/
fn void Pcg128Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_long, bytes);
}
fn void Pcg128RandomState.set_seed(&self, uint128 seed)
{
*self = (Pcg128RandomState)seed;
}
fn ulong Pcg128RandomState.next_long(&self)
{
const ROT_SHIFT = 64 - 6;
uint128* s = (uint128*)pcg;
uint128* s = (uint128*)self;
uint128 xor = *s ^ *s >> ((128 - ROT_SHIFT) / 2);
char rot = (char)(*s >> (128 - 6));
*s = *s * MUL_LCG128 + ODD_PHI128;
@@ -34,17 +63,46 @@ fn ulong Pcg128_64.next(&pcg)
// -------------------------------- Pcg64_32 --------------------------------
def Pcg64_32 = distinct ulong;
fn void Pcg64_32.seed(&pcg, char[8] seed)
struct Pcg64Random
{
*pcg = bitcast(seed, Pcg64_32);
inline Random random;
Pcg64RandomState state;
}
fn uint Pcg64_32.next(&pcg)
def Pcg64RandomState = distinct ulong;
const RandomInterface PCG_64_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Pcg64Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Pcg64Random.next_bytes,
};
fn void Pcg64Random.init(&self)
{
self.random.fns = &PCG_64_RANDOM_INTERFACE;
}
fn void Pcg64Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(ulong, input));
}
/**
* @require bytes.len > 0
**/
fn void Pcg64Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_int, bytes);
}
fn void Pcg64RandomState.set_seed(&self, ulong seed)
{
*self = (Pcg64RandomState)seed;
}
fn uint Pcg64RandomState.next_int(&self)
{
const ROT_SHIFT = 32 - 5;
ulong* s = (ulong*)pcg;
ulong* s = (ulong*)self;
ulong xor = *s ^ *s >> ((64 - ROT_SHIFT) / 2);
char rot = (char)(*s >> (64 - 5));
*s = *s * MUL_LCG64 + ODD_PHI64;
@@ -54,17 +112,46 @@ fn uint Pcg64_32.next(&pcg)
// -------------------------------- Pcg32_16 --------------------------------
def Pcg32_16 = distinct uint;
fn void Pcg32_16.seed(&pcg, char[4] seed)
struct Pcg32Random
{
*pcg = bitcast(seed, Pcg32_16);
inline Random random;
Pcg32RandomState state;
}
fn ushort Pcg32_16.next(&pcg)
def Pcg32RandomState = distinct uint;
const RandomInterface PCG_32_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Pcg32Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Pcg32Random.next_bytes,
};
fn void Pcg32Random.init(&self)
{
self.random.fns = &PCG_32_RANDOM_INTERFACE;
}
fn void Pcg32Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(uint, input));
}
/**
* @require bytes.len > 0
**/
fn void Pcg32Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_short, bytes);
}
fn void Pcg32RandomState.set_seed(&self, uint seed)
{
*self = (Pcg32RandomState)seed;
}
fn ushort Pcg32RandomState.next_short(&self)
{
const ROT_SHIFT = 16 - 4;
uint* s = (uint*)pcg;
uint* s = (uint*)self;
uint xor = *s ^ *s >> ((32 - ROT_SHIFT) / 2);
char rot = (char)(*s >> (32 - 4));
*s = *s * MUL_LCG32 + ODD_PHI32;
@@ -74,17 +161,46 @@ fn ushort Pcg32_16.next(&pcg)
// -------------------------------- Pcg16_8 --------------------------------
def Pcg16_8 = distinct ushort;
fn void Pcg16_8.seed(&pcg, char[2] seed)
struct Pcg16Random
{
*pcg = bitcast(seed, Pcg16_8);
inline Random random;
Pcg16RandomState state;
}
fn char Pcg16_8.next(&pcg)
def Pcg16RandomState = distinct ushort;
const RandomInterface PCG_16_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Pcg16Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Pcg16Random.next_bytes,
};
fn void Pcg16Random.init(&self)
{
self.random.fns = &PCG_16_RANDOM_INTERFACE;
}
fn void Pcg16Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(ushort, input));
}
/**
* @require bytes.len > 0
**/
fn void Pcg16Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_byte, bytes);
}
fn void Pcg16RandomState.set_seed(&self, ushort seed)
{
*self = (Pcg16RandomState)seed;
}
fn char Pcg16RandomState.next_byte(&self)
{
const ROT_SHIFT = 8 - 3;
ushort* s = (ushort*)pcg;
ushort* s = (ushort*)self;
ushort xor = *s ^ *s >> ((16 - ROT_SHIFT) / 2);
char rot = (char)(*s >> (16 - 3));
*s = *s * MUL_LCG16 + ODD_PHI16;

View File

@@ -1,53 +1,66 @@
module std::math;
module std::math::random;
const ODD_PHI64 @local = 0x9e3779b97f4a7c15;
const MUL_MCG64 @local = 0xf1357aea2e62a9c5;
const MUL_LCG64 @local = 0xd1342543de82ef95;
macro make_seed($Type, char[] input)
{
$Type return_value;
seeder(input, @to_byte_view(return_value));
return return_value;
}
// TODO: Make endian independent
fn char[] seeder(usz outChars, char[] input)
/**
* @param [in] input
* @param [inout] out_buffer
**/
fn void seeder(char[] input, char[] out_buffer)
{
$if env::BIG_ENDIAN:
$echo("Please note that the seeding function behaves differently on BE architectures.");
$endif
// Init words
ulong[] words = malloc(ulong, (outChars + 7) / 8);
words[..] = ODD_PHI64;
// Add word at a time
for (usz i = 0; i < input.len / 8; i++)
usz out_chars = out_buffer.len;
@pool()
{
usz j = i % words.len;
words[j] -= bitcast(*(char[8]*)&input[i * 8], ulong) * MUL_LCG64;
words[j] ^= words[j] >> 25;
}
ulong[] words = tmalloc(ulong, (out_chars + 7) / 8);
words[..] = ODD_PHI64;
// Add rest of the bytes
usz remaining = input.len - input.len / 8 * 8;
if (remaining)
{
ulong rest = MUL_MCG64;
mem::copy(&rest, &input[^remaining], remaining);
words[^1] -= rest * MUL_LCG64;
words[^1] ^= words[^1] >> 25;
}
// Add word at a time
for (usz i = 0; i < input.len / 8; i++)
{
usz j = i % words.len;
words[j] -= bitcast(*(char[8]*)&input[i * 8], ulong) * MUL_LCG64;
words[j] ^= words[j] >> 25;
}
// Mix between words
for (isz i = words.len * 2 - 1; i >= 0; i--)
{
isz j = i % words.len;
words[j] -= words[(i + 1) % words.len] * MUL_LCG64;
words[j] ^= words[j] >> 25;
}
// Add rest of the bytes
usz remaining = input.len - input.len / 8 * 8;
if (remaining)
{
ulong rest = MUL_MCG64;
mem::copy(&rest, &input[^remaining], remaining);
words[^1] -= rest * MUL_LCG64;
words[^1] ^= words[^1] >> 25;
}
// Mix within words
for (usz i = 0; i < 2; i++)
{
usz j = i % words.len;
words[j] *= MUL_MCG64;
words[j] ^= words[j] >> 25;
}
// Mix between words
for (isz i = words.len * 2 - 1; i >= 0; i--)
{
isz j = i % words.len;
words[j] -= words[(i + 1) % words.len] * MUL_LCG64;
words[j] ^= words[j] >> 25;
}
return ((char*)words.ptr)[:words.len * 8];
// Mix within words
for (usz i = 0; i < 2; i++)
{
usz j = i % words.len;
words[j] *= MUL_MCG64;
words[j] ^= words[j] >> 25;
}
out_buffer[..] = ((char*)words.ptr)[:out_chars];
};
}

View File

@@ -10,16 +10,46 @@ const ODD_PHI8 @local = 0x9f;
// -------------------------------- Sfc128 --------------------------------
def Sfc128 = distinct uint128[4];
fn void Sfc128.seed(&sfc, char[16 * 4] seed)
struct Sfc128Random
{
*sfc = bitcast(seed, Sfc128);
inline Random random;
Sfc128RandomState state;
}
fn uint128 Sfc128.next(&sfc) // TODO: Find good constant
def Sfc128RandomState = distinct uint128[4];
const RandomInterface SFC_128_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Sfc128Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Sfc128Random.next_bytes,
};
fn void Sfc128Random.init(&self)
{
uint128* s = (uint128[4]*)sfc;
self.random.fns = &SFC_128_RANDOM_INTERFACE;
}
fn void Sfc128Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(uint128[4], input));
}
/**
* @require bytes.len > 0
**/
fn void Sfc128Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_int128, bytes);
}
fn void Sfc128RandomState.set_seed(&self, uint128[4] seed)
{
*self = (Sfc128RandomState)seed;
}
fn uint128 Sfc128RandomState.next_int128(&self) // TODO: Find good constant
{
uint128* s = (uint128[4]*)self;
uint128 result = s[0] + s[1] + s[3];
s[0] = s[1] ^ s[1] >> 11;
s[1] = s[2] + s[2] << 3;
@@ -31,16 +61,46 @@ fn uint128 Sfc128.next(&sfc) // TODO: Find good constant
// -------------------------------- Sfc64 --------------------------------
def Sfc64 = distinct ulong[4];
fn void Sfc64.seed(&sfc, char[8 * 4] seed)
struct Sfc64Random
{
*sfc = bitcast(seed, Sfc64);
inline Random random;
Sfc64RandomState state;
}
fn ulong Sfc64.next(&sfc)
def Sfc64RandomState = distinct ulong[4];
const RandomInterface SFC_64_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Sfc64Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Sfc64Random.next_bytes,
};
fn void Sfc64Random.init(&self)
{
ulong* s = (ulong[4]*)sfc;
self.random.fns = &SFC_64_RANDOM_INTERFACE;
}
fn void Sfc64Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(ulong[4], input));
}
/**
* @require bytes.len > 0
**/
fn void Sfc64Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_long, bytes);
}
fn void Sfc64RandomState.set_seed(&self, ulong[4] seed)
{
*self = (Sfc64RandomState)seed;
}
fn ulong Sfc64RandomState.next_long(&self)
{
ulong* s = (ulong[4]*)self;
ulong result = s[0] + s[1] + s[3];
s[0] = s[1] ^ s[1] >> 11;
s[1] = s[2] + s[2] << 3;
@@ -52,14 +112,44 @@ fn ulong Sfc64.next(&sfc)
// -------------------------------- Sfc32 --------------------------------
def Sfc32 = distinct uint[4];
fn void Sfc32.seed(&sfc, char[4 * 4] seed)
struct Sfc32Random
{
*sfc = bitcast(seed, Sfc32);
inline Random random;
Sfc32RandomState state;
}
fn uint Sfc32.next(&sfc)
def Sfc32RandomState = distinct uint[4];
const RandomInterface SFC_32_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Sfc32Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Sfc32Random.next_bytes,
};
fn void Sfc32Random.init(&self)
{
self.random.fns = &SFC_32_RANDOM_INTERFACE;
}
fn void Sfc32Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(uint[4], input));
}
/**
* @require bytes.len > 0
**/
fn void Sfc32Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_int, bytes);
}
fn void Sfc32RandomState.set_seed(&self, uint[4] seed)
{
*self = (Sfc32RandomState)seed;
}
fn uint Sfc32RandomState.next_int(&sfc)
{
uint* s = (uint[4]*)sfc;
uint result = s[0] + s[1] + s[3];
@@ -73,16 +163,45 @@ fn uint Sfc32.next(&sfc)
// -------------------------------- Sfc16 --------------------------------
def Sfc16 = distinct ushort[4];
fn void Sfc16.seed(&sfc, char[2 * 4] seed)
struct Sfc16Random
{
*sfc = bitcast(seed, Sfc16);
inline Random random;
Sfc16RandomState state;
}
fn ushort Sfc16.next(&sfc)
def Sfc16RandomState = distinct ushort[4];
const RandomInterface SFC_16_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Sfc16Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Sfc16Random.next_bytes,
};
fn void Sfc16Random.init(&self)
{
ushort* s = (ushort[4]*)sfc;
self.random.fns = &SFC_16_RANDOM_INTERFACE;
}
fn void Sfc16Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(ushort[4], input));
}
/**
* @require bytes.len > 0
**/
fn void Sfc16Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_short, bytes);
}
fn void Sfc16RandomState.set_seed(&self, ushort[4] seed)
{
*self = (Sfc16RandomState)seed;
}
fn ushort Sfc16RandomState.next_short(&seed)
{
ushort* s = (ushort[4]*)seed;
ushort result = s[0] + s[1] + s[3];
s[0] = s[1] ^ s[1] >> 2;
s[1] = s[2] + s[2] << 3;
@@ -94,16 +213,45 @@ fn ushort Sfc16.next(&sfc)
// -------------------------------- Sfc8 --------------------------------
def Sfc8 = distinct char[4];
fn void Sfc8.seed(&sfc, char[1 * 4] seed)
struct Sfc8Random
{
*sfc = bitcast(seed, Sfc8);
inline Random random;
Sfc8RandomState state;
}
fn char Sfc8.next(&sfc) // TODO: Find better constants
def Sfc8RandomState = distinct char[4];
const RandomInterface SFC_8_RANDOM_INTERFACE @local = {
.seed_fn = (RandomSeedFn)&Sfc8Random.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&Sfc8Random.next_bytes,
};
fn void Sfc8Random.init(&self)
{
char* s = (char[4]*)sfc;
self.random.fns = &SFC_8_RANDOM_INTERFACE;
}
fn void Sfc8Random.set_seed(&self, char[] input)
{
self.state.set_seed(random::make_seed(char[4], input));
}
/**
* @require bytes.len > 0
**/
fn void Sfc8Random.next_bytes(&self, char[] bytes)
{
@random_value_to_bytes(self.state.next_byte, bytes);
}
fn void Sfc8RandomState.set_seed(&self, char[4] seed)
{
*self = (Sfc8RandomState)seed;
}
fn char Sfc8RandomState.next_byte(&self) // TODO: Find better constants
{
char* s = (char[4]*)self;
char result = s[0] + s[1] + s[3];
s[0] = s[1] ^ s[1] >> 1;
s[1] = s[2] + s[2] << 2;

View File

@@ -1,38 +1,49 @@
module std::math;
def SimpleRandom = distinct ulong;
struct SimpleRandom
{
inline Random random;
SimpleRandomState state;
}
const long SIMPLE_RANDOM_MULTIPLIER @local = 0x5DEECE66D;
const long SIMPLE_RANDOM_ADDEND @local = 0xB;
const long SIMPLE_RANDOM_MASK @local = (1u64 << 48) - 1;
def SimpleRandomState = distinct ulong;
RandomInterface simple_random_interface = {
.seed_fn = fn (random, seed) => ((SimpleRandom*)random.state).set_random_seed(seed),
.next_fn = fn (random, bits) => ((SimpleRandom*)random.state).next_random(bits)
.seed_fn = (RandomSeedFn)&SimpleRandom.set_seed,
.next_bytes_fn = (RandomNextBytesFn)&SimpleRandom.next_bytes
};
fn Random SimpleRandom.as_random(&random)
/**
* @require bytes.len > 0
**/
fn void SimpleRandom.next_bytes(&self, char[] bytes)
{
return { .fns = simple_random_interface, .state = random };
@random_value_to_bytes(self.state.next_int, bytes);
}
fn uint SimpleRandom.next_random(&r, int bits) @dynamic
{
ulong nextseed = ((ulong)*r * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK;
*r = (SimpleRandom)nextseed;
return (uint)(nextseed >> (48 - bits));
}
fn void SimpleRandom.set_seed(&r, ulong seed)
{
*r = (SimpleRandom)((seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK);
}
fn void SimpleRandom.set_random_seed(&r, char[] seed) @dynamic
fn void SimpleRandom.set_seed(&self, char[] seed)
{
char[8] full;
foreach (i, c : seed)
{
full[i % 8] ^= c;
}
r.set_seed(bitcast(full, ulong));
self.state.set_seed(bitcast(full, ulong));
}
fn void SimpleRandomState.set_seed(&self, ulong seed)
{
*self = (SimpleRandomState)(seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK;
}
fn uint SimpleRandomState.next_int(&self)
{
ulong nextseed = ((ulong)*self * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK;
*self = (SimpleRandomState)nextseed;
return (uint)(nextseed >> (48 - 32));
}
const long SIMPLE_RANDOM_MULTIPLIER @local = 0x5DEECE66D;
const long SIMPLE_RANDOM_ADDEND @local = 0xB;
const long SIMPLE_RANDOM_MASK @local = (1u64 << 48) - 1;