summaryrefslogtreecommitdiff
path: root/lib/std/rand.myr
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/rand.myr')
-rw-r--r--lib/std/rand.myr185
1 files changed, 185 insertions, 0 deletions
diff --git a/lib/std/rand.myr b/lib/std/rand.myr
new file mode 100644
index 0000000..2e8c73e
--- /dev/null
+++ b/lib/std/rand.myr
@@ -0,0 +1,185 @@
+use "die.use"
+use "types.use"
+use "alloc.use"
+/*
+ Translated from C by Ori Bernstein
+ */
+
+/*
+ A C-program for MT19937, with initialization improved 2002/1/26.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Any feedback is very welcome.
+ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+ */
+
+pkg std =
+ type rng
+
+ const mksrng : (seed : uint32 -> rng#)
+ const delrng : (rng : rng# -> void)
+ generic rand : (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+ generic randN : (rng : rng# -> @a::(numeric,integral))
+ const randbytes : (rng : rng#, buf : byte[:] -> size)
+ const rand32 : (rng : rng# -> uint32)
+;;
+
+type rng = struct
+ state : uint32[624]
+ i : uint32
+;;
+
+/* allocates and initializes a random number generator */
+const mksrng = {seed
+ var rng
+
+ rng = alloc()
+ init(rng, seed)
+ -> rng
+}
+
+const delrng = {rng
+ free(rng)
+}
+
+/* initializes a random number generator from the seed `seed`. */
+const init = {rng, seed
+ var i
+
+ for i = 0; i < 624; i++
+ rng.state[i] = seed
+ seed = 1812433253 * (seed ^ (seed >> 30)) + i + 1
+ ;;
+ rng.i = i
+}
+
+/*
+ Generates a random integer from `rng` in the range [lo, hi),
+ returning the value. The range [lo, hi) must be positive,
+ nonempty, and the difference between hi and lo must be
+ less then 2^(type_bits - 1)
+*/
+generic rand = {rng, lo, hi -> @a::(integral,numeric)
+ var span, lim
+ var maxrand
+ var val
+
+ assert(hi - lo > 0, "rand.myr: range for random values must be >= 1")
+
+ span = hi - lo
+ maxrand = (1 << (8*sizeof(@a))) - 1 /* max for signed value */
+ if maxrand < 0 /* signed */
+ maxrand = (1 << (8*sizeof(@a)-1)) - 1 /* max for signed value */
+ ;;
+
+ lim = (maxrand/span)*span
+ val = (randN(rng) & maxrand)
+ while val > lim
+ val = (randN(rng) & maxrand)
+ ;;
+ -> val % span + lo
+}
+
+/*
+ Generates a random integer of any size from the
+ random number generator `rng`. The returned value
+ may be negative, if the type is signed.
+*/
+generic randN = {rng -> @a::(integral,numeric)
+ var i, val
+
+ val = 0
+ for i = 0; i < sizeof(@a)/4; i++
+ val <<= 8*sizeof(@a)
+ val |= rand32(rng) castto(@a::(integral,numeric))
+ ;;
+ -> val
+}
+
+/*
+ generates a 32 bit unsigned random number
+ from the random number generator `rng`.
+*/
+const rand32 = {rng
+ var x
+
+ if rng.i == 624
+ next(rng)
+ ;;
+ x = rng.state[rng.i]
+ rng.i++
+
+ x ^= x >> 11
+ x ^= (x << 7) & 0x9D2C5680
+ x ^= (x << 15) & 0xEFC60000
+ -> x ^ (x >> 18)
+}
+
+const randbytes = {rng, buf
+ var i, n, r
+
+ n = 0
+ for i = 0; i < buf.len/4; i++
+ r = rand32(rng)
+ buf[n++] = (r >> 0 & 0xff) castto(byte)
+ buf[n++] = (r >> 8 & 0xff) castto(byte)
+ buf[n++] = (r >> 16 & 0xff) castto(byte)
+ buf[n++] = (r >> 32 & 0xff) castto(byte)
+ ;;
+ r = rand32(rng)
+ for ; n != buf.len; n++
+ buf[n++] = (r & 0xff) castto(byte)
+ r >>= 8
+ ;;
+ -> n
+
+}
+
+/* updates random number generator state when we tick over. */
+const next = {rng
+ var k
+ var y
+
+ for k = 0; k < 227; k++
+ y = (rng.state[k] & 0x80000000) | (rng.state[k + 1] & 0x7FFFFFFF)
+ rng.state[k] = rng.state[k + 397] ^ (y >> 1) ^ ((y & 1) * 0x9908B0DF)
+ ;;
+ for ; k < 623; k++
+ y = (rng.state[k] & 0x80000000) | (rng.state[k + 1] & 0x7FFFFFFF)
+ rng.state[k] = rng.state[k - 227] ^ (y >> 1) ^ ((y & 1) * 0x9908B0DF);
+ ;;
+ y = (rng.state[623] & 0x80000000) | (rng.state[0] & 0x7FFFFFFF)
+ rng.state[623] = rng.state[396] ^ (y >> 1) ^ ((y & 1) * 0x9908B0DF);
+ rng.i = 0
+}