shithub: mc

Download patch

ref: 458b9914044d8ddcdaea19e875a76493494b60f0
parent: 93123de228f52f9294dcba6748d8e8e9a8446335
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Sep 10 09:28:44 EDT 2016

Clean up the RNG.

	Now it's less complex/shitty.

--- a/lib/std/rand.myr
+++ b/lib/std/rand.myr
@@ -1,53 +1,12 @@
+use "alloc"
+use "assert"
 use "die"
 use "extremum"
-use "assert"
-use "types"
-use "alloc"
+use "mk"
 use "now"
+use "putint"
+use "types"
 
-/*
-   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
 
@@ -56,153 +15,91 @@
 
 	generic rand	: (lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
 	generic randnum	: (-> @a::(numeric,integral))
-	const randbytes	: (buf : byte[:]	-> size)
+	const randbytes	: (buf : byte[:] -> void)
 
 	generic rngrand	: (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
 	generic rngrandnum	: (rng : rng# -> @a::(numeric,integral))
-	const rngrandbytes	: (rng : rng#, buf : byte[:]	-> size)
+	const rngrandbytes	: (rng : rng#, buf : byte[:] -> void)
 ;;
 
 type rng = struct
-	state	: uint32[624]
-	i	: uint32
+	s0 : uint64
+	s1 : uint64
 ;;
 
-var _rng : rng#
+var _rng
 
+generic rand	= {lo, hi;	-> rngrand(&_rng, lo, hi)}
+generic randnum	= {;	-> rngrandnum(&_rng)}
+const randbytes	= {buf;	-> rngrandbytes(&_rng, buf)}
+
 const __init__ = {
-	_rng = mksrng((now() : uint32))
+	_rng.s0 = (now() : uint64)
+	_rng.s1 = (now() : uint64)
 }
 
-/* allocates and initializes a random number generator */
-const mksrng = {seed
-	var rng
-
-	rng = alloc()
-	init(rng, seed)
-	-> rng
+const mksrng = {seed : uint32 -> rng#
+	-> std.mk([
+		.s0=(seed & 0xffff : uint64),
+		.s1=(seed&0xffff0000>>16 : uint64)
+	])
 }
 
-const freerng = {rng
-	free(rng)
+const freerng	= {r
+	std.free(r)
 }
 
-/* initializes a random number generator from the seed `seed`. */
-const init = {rng, seed
-	for var i = 0; i < 624; i++
-		rng.state[i] = seed
-		seed = 1812433253 * (seed ^ (seed >> 30)) + i + 1
-	;;
-	rng.i = 624
-}
-
-generic rand = {lo, hi
-	-> rngrand(_rng, lo, hi)
-}
-
-generic randnum = {
-	-> rngrandnum(_rng)
-}
-
-const randbytes = {buf
-	-> rngrandbytes(_rng, buf)
-}
-
-/*
-   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 rngrand = {rng, lo, hi -> @a::(integral,numeric)
-	var span, lim
-	var maxrand
-	var val
-
+generic rngrand = {rng, lo, hi
+	var span, lim, val, max
+	
 	span = abs(hi - lo)
-	assert(span > 0, "rand.myr: range for random values must be >= 1, got hi={}, lo={}\n", hi, lo)
-
-	maxrand = ~0
-	if maxrand < 0 /* if we're signed the maximum value is different */
-		maxrand = (1 << (8*sizeof(@a)-1)) - 1 /* max for signed value */
+	max = ~0
+	/* if ~0 is negative, we have a signed value with a different max */
+	if max < 0
+	        max = (1 << (8*sizeof(@a)-1)) - 1
 	;;
-
-	lim = (maxrand/span)*span
-	val = (rngrandnum(rng) & maxrand)
-	while val > lim 
-		val = (rngrandnum(rng) & maxrand)
+	
+	lim = (max/span)*span
+	val = (rngrandnum(rng) & max)
+	while val > lim
+	        val = (rngrandnum(rng) & max)
 	;;
 	-> 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 rngrandnum = {rng -> @a::(integral,numeric)
-	var val
-
-	val = 0
-	for var i = 0; i < sizeof(@a)/4; i++
-		val <<= 8*sizeof(@a)
-		val |= (rand32(rng)  : @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 rngrandbytes = {rng, buf
-	var n, r
+	var n, r : uint64
 
 	n = 0
-	for var i = 0; i < buf.len/4; i++
-		r = rand32(rng)
-		buf[n++] = (r >>  0 & 0xff : byte)
-		buf[n++] = (r >>  8 & 0xff : byte)
-		buf[n++] = (r >> 16 & 0xff : byte)
-		buf[n++] = (r >> 32 & 0xff : byte)
+	for var i = 0; i + 8 < buf.len/8; i++
+		r = rngrandnum(rng)
+		putle64(buf[n:n+8], r)
+		n += 8
 	;;
-	r = rand32(rng)
+	r = rngrandnum(rng)
 	for ; n != buf.len; n++
 		buf[n] = (r & 0xff : 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
+/*
+Generate a number using the xoroshiro algorithm, as
+designed by David Blackman and Sebastiano Vigna.
+
+See http://xoroshiro.di.unimi.it/ for details.
+*/
+generic rngrandnum = {rng -> @a::(numeric,integral)
+	var s0, s1, r
+
+	s0 = rng.s0
+	s1 = rng.s1
+
+	r = s0 + s1
+	s1 ^= s0
+
+	rng.s0 = (s0 << 55 | s0 >> 9) ^ s1 ^ (s1 << 14)
+	rng.s1 = (s1 << 36 | s1 >> 28)
+	-> (r : @a::(numeric,integral))
 }