diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3 index a1ef07d4b..a814d9659 100644 --- a/lib/std/libc/libc.c3 +++ b/lib/std/libc/libc.c3 @@ -52,7 +52,6 @@ extern fn int unsetenv(ZString name); extern fn int system(char* str); extern fn void bsearch(void* key, void *base, usz items, usz size, CompareFunction compare); extern fn void qsort(void* base, usz items, usz size, CompareFunction compare); -extern fn int abs(int x); extern fn DivResult div(int numer, int denom); extern fn long labs(long x); extern fn LongDivResult ldiv(long number, long denom); diff --git a/lib/std/math/math.random.c3 b/lib/std/math/math.random.c3 new file mode 100644 index 000000000..c74e1d9b6 --- /dev/null +++ b/lib/std/math/math.random.c3 @@ -0,0 +1,119 @@ +module std::math; + +struct Random +{ + RandomInterface fns; + void* state; +} + +typedef RandomSeedFn = fn void(Random*, char[] seed); +typedef RandomNextBytesFn = fn void(Random*, char[] buffer); +typedef RandomNextFn = fn uint(Random*, int bits); + +struct RandomInterface +{ + RandomSeedFn seed_fn; + RandomNextBytesFn next_bytes_fn; + RandomNextFn next_fn; +} + +/** + * @param [&inout] random + * @param [inout] buffer + **/ +fn void Random.next_bytes(Random* 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."); +} + +/** + * @param [&inout] random + * @require bits >= 0 && bits <= 32 + **/ +fn uint Random.next(Random* random, int bits) +{ + 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; +} + +/** + * @param [&inout] random + **/ +fn ulong Random.next_long(Random* random) +{ + char[8] buffer; + random.next_bytes(&buffer); + return bitcast(buffer, ulong); +} + +/** + * @param [&inout] random + **/ +fn void Random.set_seed(Random* random, long seed) +{ + random.fns.seed_fn(random, &&bitcast(seed, char[8])) @inline; +} + +/** + * @param [&inout] random + * @param [in] seed + **/ +fn void Random.set_seeds(Random* random, char[] seed) +{ + random.fns.seed_fn(random, seed); +} + +/** + * @param [&inout] random + **/ +fn bool Random.next_bool(Random* random) +{ + return random.next(1) != 0; +} + +fn float Random.next_float(Random* r) +{ + return r.next(24) / (float)(1 << 24); +} + +fn double Random.next_double(Random* r) +{ + return (((long)(r.next(26)) << 27) + r.next(27)) * 0x1.0p-53; +} + +fn uint Random.next_int(Random* r) +{ + return r.next(32) @inline; +} diff --git a/lib/std/math/math.simple_random.c3 b/lib/std/math/math.simple_random.c3 deleted file mode 100644 index 7b026571a..000000000 --- a/lib/std/math/math.simple_random.c3 +++ /dev/null @@ -1,47 +0,0 @@ -module std::math; - -struct SimpleRandom -{ - long seed; -} - -const long SIMPLE_RANDOM_MULTIPLIER @private = 0x5DEECE66D; -const long SIMPLE_RANDOM_ADDEND @private = 0xB; -const long SIMPLE_RANDOM_MASK @private = (1i64 << 48) - 1; - -fn long simple_random_initial_scramble(long seed) @private -{ - return (seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK; -} - -fn int SimpleRandom.next(SimpleRandom* r, int bits) @private -{ - long nextseed = (r.seed * SIMPLE_RANDOM_MULTIPLIER + SIMPLE_RANDOM_ADDEND) & SIMPLE_RANDOM_MASK; - r.seed = nextseed; - return (int)nextseed >> (48 - bits); -} - -fn void SimpleRandom.set_seed(SimpleRandom* r, long seed) -{ - r.seed = simple_random_initial_scramble(seed); -} - -fn int SimpleRandom.next_int(SimpleRandom* r) -{ - return r.next(32) @inline; -} - -fn bool SimpleRandom.next_bool(SimpleRandom* r) -{ - return r.next(1) != 0; -} - -fn float SimpleRandom.next_float(SimpleRandom* r) -{ - return r.next(24) / (float)(1 << 24); -} - -fn double SimpleRandom.next_double(SimpleRandom* r) -{ - return (((long)(r.next(26)) << 27) + r.next(27)) * 0x1.0p-53; -} diff --git a/lib/std/math/random/math.simple_random.c3 b/lib/std/math/random/math.simple_random.c3 new file mode 100644 index 000000000..c52cdb4c6 --- /dev/null +++ b/lib/std/math/random/math.simple_random.c3 @@ -0,0 +1,38 @@ +module std::math; + +typedef SimpleRandom = distinct ulong; + +const long SIMPLE_RANDOM_MULTIPLIER @local = 0x5DEECE66D; +const long SIMPLE_RANDOM_ADDEND @local = 0xB; +const long SIMPLE_RANDOM_MASK @local = (1u64 << 48) - 1; + +RandomInterface simple_random_interface = { + .seed_fn = fn (random, seed) => ((SimpleRandom*)random.state).set_seeds(seed), + .next_fn = fn (random, bits) => ((SimpleRandom*)random.state).next(bits) +}; + +fn Random SimpleRandom.as_random(SimpleRandom* random) +{ + return { .fns = simple_random_interface, .state = random }; +} + +fn uint SimpleRandom.next(SimpleRandom* r, int bits) +{ + 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(SimpleRandom* r, ulong seed) +{ + *r = (SimpleRandom)((seed ^ SIMPLE_RANDOM_MULTIPLIER) & SIMPLE_RANDOM_MASK); +} +fn void SimpleRandom.set_seeds(SimpleRandom* r, char[] seed) +{ + char[8] full; + foreach (i, c : seed) + { + full[i % 8] ^= c; + } + r.set_seed(bitcast(full, ulong)); +}