aboutsummaryrefslogtreecommitdiff
path: root/core/math
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2018-01-17 19:09:22 +0000
committergingerBill <bill@gingerbill.org>2018-01-17 19:09:22 +0000
commitb3734a5f771e46df1d8bde4a187fb8a4e93e6612 (patch)
treedcff33f003c5caf01b89841d3e167d0871880d9a /core/math
parent419ab6f00c5396c1296a78e931693ba38d7ea102 (diff)
Add math/rand.odin
Diffstat (limited to 'core/math')
-rw-r--r--core/math/rand.odin60
1 files changed, 60 insertions, 0 deletions
diff --git a/core/math/rand.odin b/core/math/rand.odin
new file mode 100644
index 000000000..4862ad496
--- /dev/null
+++ b/core/math/rand.odin
@@ -0,0 +1,60 @@
+Rand :: struct {
+ state: u64,
+ inc: u64,
+}
+
+init :: proc(r: ^Rand, seed: u64 = 8675309) {
+ r.state = 0;
+ r.inc = (seed << 1) | 1;
+ _random(r);
+ r.state += seed;
+ _random(r);
+}
+
+_random :: proc(r: ^Rand) -> u32 {
+ old_state := r.state;
+ r.state = old_state * 6364136223846793005 + (r.inc|1);
+ xor_shifted := u32(((old_state>>18) ~ old_state) >> 27);
+ rot := u32(old_state >> 59);
+ return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31));
+}
+
+uint32 :: proc(r: ^Rand) -> u32 { return _random(r); }
+
+uint64 :: proc(r: ^Rand) -> u64 {
+ a := u64(_random(r));
+ b := u64(_random(r));
+ return (a<<32) | b;
+}
+
+int31 :: proc(r: ^Rand) -> i32 { return i32(uint32(r) << 1 >> 1); }
+int63 :: proc(r: ^Rand) -> i64 { return i64(uint64(r) << 1 >> 1); }
+
+int31_max :: proc(r: ^Rand, n: i32) -> i32 {
+ if n <= 0 do panic("Invalid argument to int31_max");
+ if n&(n-1) == 0 {
+ return int31(r) & (n-1);
+ }
+ max := i32((1<<31) - 1 - (1<<31)&u32(n));
+ v := int31(r);
+ for v > max {
+ v = int31(r);
+ }
+ return v % n;
+}
+
+int63_max :: proc(r: ^Rand, n: i64) -> i64 {
+ if n <= 0 do panic("Invalid argument to int63_max");
+ if n&(n-1) == 0 {
+ return int63(r) & (n-1);
+ }
+ max := i64((1<<63) - 1 - (1<<63)&u64(n));
+ v := int63(r);
+ for v > max {
+ v = int63(r);
+ }
+ return v % n;
+}
+
+float64 :: proc(r: ^Rand) -> f64 { return f64(int63_max(r, 1<<53)) / (1 << 53); }
+float32 :: proc(r: ^Rand) -> f32 { return f32(float64(r)); }