From f2e0698608bbbf84a8a9bfd69ffae54c5128d860 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Mon, 19 Jul 2021 11:45:51 -0700 Subject: [PATCH] switch to fastrand (not actually any faster) --- combinators.nim | 4 ++-- fastrand.nim | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/combinators.nim b/combinators.nim index 903d1a7..01b4c0d 100644 --- a/combinators.nim +++ b/combinators.nim @@ -1,5 +1,5 @@ import algorithm, random, sugar -import fixedseq, game +import fastrand, fixedseq, game proc nextPermutation(x: var FixedSeq): bool = @@ -93,4 +93,4 @@ proc randomFuture*(dice: FixedSeq, r: var Rand): FixedSeq[5, Die, int8] = result.initFixedSeq let order = dice.dup(shuffle(r)) for i, color in order: - result.add((color, r.rand(1..3))) + result.add((color, r.fastRand(1..3))) diff --git a/fastrand.nim b/fastrand.nim index 9480411..93f02e1 100644 --- a/fastrand.nim +++ b/fastrand.nim @@ -17,13 +17,27 @@ proc formatRate(n: Natural, d: Duration): string = result = formatNum(1_000_000'f64 * n.float64 / d.inMicroseconds.float64) -proc fastRand(r: var Rand, x: Natural): uint64 = - # return ((r.next shr 32) * x.uint64) shr 32 - let x = x.uint64 - if x <= (uint64.high shl 32): - return ((r.next shr 32) * x.uint64) shr 32 +const upperBound = uint64(uint32.high) + + +proc fastRand*[T: Natural](r: var Rand, x: T): T = + # Nim ranges are usually inclusive, but this algorithm is exclusive + let x = x.uint64 + 1 + let num = if x <= upperBound: + ((r.next shr 32) * x.uint64) shr 32 else: - return r.next mod x.uint64 + r.next mod x.uint64 + result = T(num) + + +proc fastRand*(r: var Rand; x, y: Natural): Natural = + let lim = (y - x) + result = fastRand(r, lim) + x + + +proc fastRand*[T](r: var Rand, slice: HSlice[T, T]): T = + let n = fastRand(r, slice.a.Natural, slice.b.Natural) + result = T(n) proc testFastRand(num = 1_000_000_000): Duration = @@ -44,9 +58,17 @@ proc testStdRand(num = 1_000_000_000): Duration = # echo "std rand execution rate: ", 1000 * num / dur.inMilliseconds.int, " generated per second." -randomize() -let runs = 100_000_000 -let fr = testFastRand(runs) -echo "fastrand execution rate: ", formatNum(1_000_000 * runs / fr.inMicroseconds.int) -let sr = testStdRand(runs) -echo "standard execution rate: ", formatNum(1_000_000 * runs / sr.inMicroseconds.int) +when isMainModule: + randomize() + var r = initRand(rand(int64)) + let runs = 100_000_000 + var totals: array[5..9, int] + for i in 1 .. runs: + let n = r.fastRand(5..9) + totals[n] += 1 + echo totals + + # let fr = testFastRand(runs) + # echo "fastrand execution rate: ", formatNum(1_000_000 * runs / fr.inMicroseconds.int) + # let sr = testStdRand(runs) + # echo "standard execution rate: ", formatNum(1_000_000 * runs / sr.inMicroseconds.int)