123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- #
- #
- # Nim's Runtime Library
- # (c) Copyright 2017 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- ## Nim's standard random number generator (RNG).
- ##
- ## Its implementation is based on the `xoroshiro128+`
- ## (xor/rotate/shift/rotate) library.
- ## * More information: http://xoroshiro.di.unimi.it
- ## * C implementation: http://xoroshiro.di.unimi.it/xoroshiro128plus.c
- ##
- ## **Do not use this module for cryptographic purposes!**
- ##
- ## Basic usage
- ## ===========
- ##
- runnableExamples:
- # Call randomize() once to initialize the default random number generator.
- # If this is not called, the same results will occur every time these
- # examples are run.
- randomize()
- # Pick a number in 0..100.
- let num = rand(100)
- doAssert num in 0..100
- # Roll a six-sided die.
- let roll = rand(1..6)
- doAssert roll in 1..6
- # Pick a marble from a bag.
- let marbles = ["red", "blue", "green", "yellow", "purple"]
- let pick = sample(marbles)
- doAssert pick in marbles
- # Shuffle some cards.
- var cards = ["Ace", "King", "Queen", "Jack", "Ten"]
- shuffle(cards)
- doAssert cards.len == 5
- ## These examples all use the default RNG. The
- ## `Rand type <#Rand>`_ represents the state of an RNG.
- ## For convenience, this module contains a default Rand state that corresponds
- ## to the default RNG. Most procs in this module which do
- ## not take in a Rand parameter, including those called in the above examples,
- ## use the default generator. Those procs are **not** thread-safe.
- ##
- ## Note that the default generator always starts in the same state.
- ## The `randomize proc <#randomize>`_ can be called to initialize the default
- ## generator with a seed based on the current time, and it only needs to be
- ## called once before the first usage of procs from this module. If
- ## `randomize` is not called, the default generator will always produce
- ## the same results.
- ##
- ## RNGs that are independent of the default one can be created with the
- ## `initRand proc <#initRand,int64>`_.
- ##
- ## Again, it is important to remember that this module must **not** be used for
- ## cryptographic applications.
- ##
- ## See also
- ## ========
- ## * `std/sysrand module <sysrand.html>`_ for a cryptographically secure pseudorandom number generator
- ## * `mersenne module <mersenne.html>`_ for the Mersenne Twister random number generator
- ## * `math module <math.html>`_ for basic math routines
- ## * `stats module <stats.html>`_ for statistical analysis
- ## * `list of cryptographic and hashing modules <lib.html#pure-libraries-hashing>`_
- ## in the standard library
- import algorithm, math
- import std/private/since
- include system/inclrtl
- {.push debugger: off.}
- when defined(js):
- type Ui = uint32
- const randMax = 4_294_967_295u32
- else:
- type Ui = uint64
- const randMax = 18_446_744_073_709_551_615u64
- type
- Rand* = object ## State of a random number generator.
- ##
- ## Create a new Rand state using the `initRand proc <#initRand,int64>`_.
- ##
- ## The module contains a default Rand state for convenience.
- ## It corresponds to the default RNG's state.
- ## The default Rand state always starts with the same values, but the
- ## `randomize proc <#randomize>`_ can be used to seed the default generator
- ## with a value based on the current time.
- ##
- ## Many procs have two variations: one that takes in a Rand parameter and
- ## another that uses the default generator. The procs that use the default
- ## generator are **not** thread-safe!
- a0, a1: Ui
- when defined(js):
- var state = Rand(
- a0: 0x69B4C98Cu32,
- a1: 0xFED1DD30u32) # global for backwards compatibility
- else:
- const DefaultRandSeed = Rand(
- a0: 0x69B4C98CB8530805u64,
- a1: 0xFED1DD3004688D67CAu64)
- # racy for multi-threading but good enough for now:
- var state = DefaultRandSeed # global for backwards compatibility
- func isValid(r: Rand): bool {.inline.} =
- ## Check whether state of `r` is valid.
- ##
- ## In `xoroshiro128+`, if all bits of `a0` and `a1` are zero,
- ## they are always zero after calling `next(r: var Rand)`.
- not (r.a0 == 0 and r.a1 == 0)
- since (1, 5):
- template randState*(): untyped =
- ## Makes the default Rand state accessible from other modules.
- ## Useful for module authors.
- state
- proc rotl(x, k: Ui): Ui =
- result = (x shl k) or (x shr (Ui(64) - k))
- proc next*(r: var Rand): uint64 =
- ## Computes a random `uint64` number using the given state.
- ##
- ## **See also:**
- ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer between zero and
- ## a given upper bound
- ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
- ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice
- ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
- ## * `skipRandomNumbers proc<#skipRandomNumbers,Rand>`_
- runnableExamples("-r:off"):
- var r = initRand(2019)
- assert r.next() == 13223559681708962501'u64 # implementation defined
- assert r.next() == 7229677234260823147'u64 # ditto
- let s0 = r.a0
- var s1 = r.a1
- result = s0 + s1
- s1 = s1 xor s0
- r.a0 = rotl(s0, 55) xor s1 xor (s1 shl 14) # a, b
- r.a1 = rotl(s1, 36) # c
- proc skipRandomNumbers*(s: var Rand) =
- ## The jump function for the generator.
- ##
- ## This proc is equivalent to `2^64` calls to `next <#next,Rand>`_, and it can
- ## be used to generate `2^64` non-overlapping subsequences for parallel
- ## computations.
- ##
- ## When multiple threads are generating random numbers, each thread must
- ## own the `Rand <#Rand>`_ state it is using so that the thread can safely
- ## obtain random numbers. However, if each thread creates its own Rand state,
- ## the subsequences of random numbers that each thread generates may overlap,
- ## even if the provided seeds are unique. This is more likely to happen as the
- ## number of threads and amount of random numbers generated increases.
- ##
- ## If many threads will generate random numbers concurrently, it is better to
- ## create a single Rand state and pass it to each thread. After passing the
- ## Rand state to a thread, call this proc before passing it to the next one.
- ## By using the Rand state this way, the subsequences of random numbers
- ## generated in each thread will never overlap as long as no thread generates
- ## more than `2^64` random numbers.
- ##
- ## **See also:**
- ## * `next proc<#next,Rand>`_
- runnableExamples("--threads:on"):
- import std/[random, threadpool]
- const spawns = 4
- const numbers = 100000
- proc randomSum(r: Rand): int =
- var r = r
- for i in 1..numbers:
- result += r.rand(0..10)
- var r = initRand(2019)
- var vals: array[spawns, FlowVar[int]]
- for val in vals.mitems:
- val = spawn randomSum(r)
- r.skipRandomNumbers()
- for val in vals:
- doAssert abs(^val - numbers * 5) / numbers < 0.1
- when defined(js):
- const helper = [0xbeac0467u32, 0xd86b048bu32]
- else:
- const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64]
- var
- s0 = Ui 0
- s1 = Ui 0
- for i in 0..high(helper):
- for b in 0 ..< 64:
- if (helper[i] and (Ui(1) shl Ui(b))) != 0:
- s0 = s0 xor s.a0
- s1 = s1 xor s.a1
- discard next(s)
- s.a0 = s0
- s.a1 = s1
- proc rand[T: uint | uint64](r: var Rand; max: T): T =
- # xxx export in future work
- if max == 0: return
- else:
- let max = uint64(max)
- when T.high.uint64 == uint64.high:
- if max == uint64.high: return T(next(r))
- while true:
- let x = next(r)
- # avoid `mod` bias
- if x <= randMax - (randMax mod max):
- return T(x mod (max + 1))
- proc rand*(r: var Rand; max: Natural): int {.benign.} =
- ## Returns a random integer in the range `0..max` using the given state.
- ##
- ## **See also:**
- ## * `rand proc<#rand,int>`_ that returns an integer using the default RNG
- ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
- ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice
- ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
- runnableExamples:
- var r = initRand(123)
- if false:
- assert r.rand(100) == 96 # implementation defined
- # bootstrap: can't use `runnableExamples("-r:off")`
- cast[int](rand(r, uint64(max)))
- # xxx toUnsigned pending https://github.com/nim-lang/Nim/pull/18445
- proc rand*(max: int): int {.benign.} =
- ## Returns a random integer in the range `0..max`.
- ##
- ## If `randomize <#randomize>`_ has not been called, the sequence of random
- ## numbers returned from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer using a
- ## provided state
- ## * `rand proc<#rand,float>`_ that returns a float
- ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice
- ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
- runnableExamples("-r:off"):
- randomize(123)
- assert [rand(100), rand(100)] == [96, 63] # implementation defined
- rand(state, max)
- proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} =
- ## Returns a random floating point number in the range `0.0..max`
- ## using the given state.
- ##
- ## **See also:**
- ## * `rand proc<#rand,float>`_ that returns a float using the default RNG
- ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
- ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice
- ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
- runnableExamples:
- var r = initRand(234)
- let f = r.rand(1.0) # 8.717181376738381e-07
- let x = next(r)
- when defined(js):
- result = (float(x) / float(high(uint32))) * max
- else:
- let u = (0x3FFu64 shl 52u64) or (x shr 12u64)
- result = (cast[float](u) - 1.0) * max
- proc rand*(max: float): float {.benign.} =
- ## Returns a random floating point number in the range `0.0..max`.
- ##
- ## If `randomize <#randomize>`_ has not been called, the sequence of random
- ## numbers returned from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `rand proc<#rand,Rand,range[]>`_ that returns a float using a
- ## provided state
- ## * `rand proc<#rand,int>`_ that returns an integer
- ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice
- ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
- runnableExamples:
- randomize(234)
- let f = rand(1.0) # 8.717181376738381e-07
- rand(state, max)
- proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T =
- ## For a slice `a..b`, returns a value in the range `a..b` using the given
- ## state.
- ##
- ## Allowed types for `T` are integers, floats, and enums without holes.
- ##
- ## **See also:**
- ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice and uses the default RNG
- ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
- ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
- ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
- runnableExamples:
- var r = initRand(345)
- assert r.rand(1..5) <= 5
- assert r.rand(-1.1 .. 1.2) >= -1.1
- assert x.a <= x.b
- when T is SomeFloat:
- result = rand(r, x.b - x.a) + x.a
- else: # Integers and Enum types
- when defined(js):
- result = cast[T](rand(r, cast[uint](x.b) - cast[uint](x.a)) + cast[uint](x.a))
- else:
- result = cast[T](rand(r, cast[uint64](x.b) - cast[uint64](x.a)) + cast[uint64](x.a))
- proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T =
- ## For a slice `a..b`, returns a value in the range `a..b`.
- ##
- ## Allowed types for `T` are integers, floats, and enums without holes.
- ##
- ## If `randomize <#randomize>`_ has not been called, the sequence of random
- ## numbers returned from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `rand proc<#rand,Rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice and uses a provided state
- ## * `rand proc<#rand,int>`_ that returns an integer
- ## * `rand proc<#rand,float>`_ that returns a floating point number
- ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
- runnableExamples:
- randomize(345)
- assert rand(1..6) <= 6
- result = rand(state, x)
- proc rand*[T: SomeInteger](t: typedesc[T]): T =
- ## Returns a random integer in the range `low(T)..high(T)`.
- ##
- ## If `randomize <#randomize>`_ has not been called, the sequence of random
- ## numbers returned from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `rand proc<#rand,int>`_ that returns an integer
- ## * `rand proc<#rand,float>`_ that returns a floating point number
- ## * `rand proc<#rand,HSlice[T: Ordinal or float or float32 or float64,T: Ordinal or float or float32 or float64]>`_
- ## that accepts a slice
- runnableExamples:
- randomize(567)
- if false: # implementation defined
- assert rand(int8) == -42
- assert rand(uint32) == 578980729'u32
- assert rand(range[1..16]) == 11
- # pending csources >= 1.4.0 or fixing https://github.com/timotheecour/Nim/issues/251#issuecomment-831599772,
- # use `runnableExamples("-r:off")` instead of `if false`
- when T is range:
- result = rand(state, low(T)..high(T))
- else:
- result = cast[T](state.next)
- proc sample*[T](r: var Rand; s: set[T]): T =
- ## Returns a random element from the set `s` using the given state.
- ##
- ## **See also:**
- ## * `sample proc<#sample,set[T]>`_ that uses the default RNG
- ## * `sample proc<#sample,Rand,openArray[T]>`_ for `openArray`s
- ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that uses a
- ## cumulative distribution function
- runnableExamples:
- var r = initRand(987)
- let s = {1, 3, 5, 7, 9}
- assert r.sample(s) in s
- assert card(s) != 0
- var i = rand(r, card(s) - 1)
- for e in s:
- if i == 0: return e
- dec(i)
- proc sample*[T](s: set[T]): T =
- ## Returns a random element from the set `s`.
- ##
- ## If `randomize <#randomize>`_ has not been called, the order of outcomes
- ## from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `sample proc<#sample,Rand,set[T]>`_ that uses a provided state
- ## * `sample proc<#sample,openArray[T]>`_ for `openArray`s
- ## * `sample proc<#sample,openArray[T],openArray[U]>`_ that uses a
- ## cumulative distribution function
- runnableExamples:
- randomize(987)
- let s = {1, 3, 5, 7, 9}
- assert sample(s) in s
- sample(state, s)
- proc sample*[T](r: var Rand; a: openArray[T]): T =
- ## Returns a random element from `a` using the given state.
- ##
- ## **See also:**
- ## * `sample proc<#sample,openArray[T]>`_ that uses the default RNG
- ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that uses a
- ## cumulative distribution function
- ## * `sample proc<#sample,Rand,set[T]>`_ for sets
- runnableExamples:
- let marbles = ["red", "blue", "green", "yellow", "purple"]
- var r = initRand(456)
- assert r.sample(marbles) in marbles
- result = a[r.rand(a.low..a.high)]
- proc sample*[T](a: openArray[T]): lent T =
- ## Returns a random element from `a`.
- ##
- ## If `randomize <#randomize>`_ has not been called, the order of outcomes
- ## from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `sample proc<#sample,Rand,openArray[T]>`_ that uses a provided state
- ## * `sample proc<#sample,openArray[T],openArray[U]>`_ that uses a
- ## cumulative distribution function
- ## * `sample proc<#sample,set[T]>`_ for sets
- runnableExamples:
- let marbles = ["red", "blue", "green", "yellow", "purple"]
- randomize(456)
- assert sample(marbles) in marbles
- result = a[rand(a.low..a.high)]
- proc sample*[T, U](r: var Rand; a: openArray[T]; cdf: openArray[U]): T =
- ## Returns an element from `a` using a cumulative distribution function
- ## (CDF) and the given state.
- ##
- ## The `cdf` argument does not have to be normalized, and it could contain
- ## any type of elements that can be converted to a `float`. It must be
- ## the same length as `a`. Each element in `cdf` should be greater than
- ## or equal to the previous element.
- ##
- ## The outcome of the `cumsum<math.html#cumsum,openArray[T]>`_ proc and the
- ## return value of the `cumsummed<math.html#cumsummed,openArray[T]>`_ proc,
- ## which are both in the math module, can be used as the `cdf` argument.
- ##
- ## **See also:**
- ## * `sample proc<#sample,openArray[T],openArray[U]>`_ that also utilizes
- ## a CDF but uses the default RNG
- ## * `sample proc<#sample,Rand,openArray[T]>`_ that does not use a CDF
- ## * `sample proc<#sample,Rand,set[T]>`_ for sets
- runnableExamples:
- from std/math import cumsummed
- let marbles = ["red", "blue", "green", "yellow", "purple"]
- let count = [1, 6, 8, 3, 4]
- let cdf = count.cumsummed
- var r = initRand(789)
- assert r.sample(marbles, cdf) in marbles
- assert(cdf.len == a.len) # Two basic sanity checks.
- assert(float(cdf[^1]) > 0.0)
- # While we could check cdf[i-1] <= cdf[i] for i in 1..cdf.len, that could get
- # awfully expensive even in debugging modes.
- let u = r.rand(float(cdf[^1]))
- a[cdf.upperBound(U(u))]
- proc sample*[T, U](a: openArray[T]; cdf: openArray[U]): T =
- ## Returns an element from `a` using a cumulative distribution function
- ## (CDF).
- ##
- ## This proc works similarly to
- ## `sample <#sample,Rand,openArray[T],openArray[U]>`_.
- ## See that proc's documentation for more details.
- ##
- ## If `randomize <#randomize>`_ has not been called, the order of outcomes
- ## from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that also utilizes
- ## a CDF but uses a provided state
- ## * `sample proc<#sample,openArray[T]>`_ that does not use a CDF
- ## * `sample proc<#sample,set[T]>`_ for sets
- runnableExamples:
- from std/math import cumsummed
- let marbles = ["red", "blue", "green", "yellow", "purple"]
- let count = [1, 6, 8, 3, 4]
- let cdf = count.cumsummed
- randomize(789)
- assert sample(marbles, cdf) in marbles
- state.sample(a, cdf)
- proc gauss*(r: var Rand; mu = 0.0; sigma = 1.0): float {.since: (1, 3).} =
- ## Returns a Gaussian random variate,
- ## with mean `mu` and standard deviation `sigma`
- ## using the given state.
- # Ratio of uniforms method for normal
- # https://www2.econ.osaka-u.ac.jp/~tanizaki/class/2013/econome3/13.pdf
- const K = sqrt(2 / E)
- var
- a = 0.0
- b = 0.0
- while true:
- a = rand(r, 1.0)
- b = (2.0 * rand(r, 1.0) - 1.0) * K
- if b * b <= -4.0 * a * a * ln(a): break
- result = mu + sigma * (b / a)
- proc gauss*(mu = 0.0, sigma = 1.0): float {.since: (1, 3).} =
- ## Returns a Gaussian random variate,
- ## with mean `mu` and standard deviation `sigma`.
- ##
- ## If `randomize <#randomize>`_ has not been called, the order of outcomes
- ## from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- result = gauss(state, mu, sigma)
- proc initRand*(seed: int64): Rand =
- ## Initializes a new `Rand <#Rand>`_ state using the given seed.
- ##
- ## Providing a specific seed will produce the same results for that seed each time.
- ##
- ## The resulting state is independent of the default RNG's state. When `seed == 0`,
- ## we internally set the seed to an implementation defined non-zero value.
- ##
- ## **See also:**
- ## * `initRand proc<#initRand>`_ that uses the current time
- ## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default RNG
- ## * `randomize proc<#randomize>`_ that initializes the default RNG using the current time
- runnableExamples:
- from std/times import getTime, toUnix, nanosecond
- var r1 = initRand(123)
- let now = getTime()
- var r2 = initRand(now.toUnix * 1_000_000_000 + now.nanosecond)
- const seedFallback0 = int32.high # arbitrary
- let seed = if seed != 0: seed else: seedFallback0 # because 0 is a fixed point
- result.a0 = Ui(seed shr 16)
- result.a1 = Ui(seed and 0xffff)
- when not defined(nimLegacyRandomInitRand):
- # calling `discard next(result)` (even a few times) would still produce
- # skewed numbers for the 1st call to `rand()`.
- skipRandomNumbers(result)
- discard next(result)
- proc randomize*(seed: int64) {.benign.} =
- ## Initializes the default random number generator with the given seed.
- ##
- ## Providing a specific seed will produce the same results for that seed each time.
- ##
- ## **See also:**
- ## * `initRand proc<#initRand,int64>`_ that initializes a Rand state
- ## with a given seed
- ## * `randomize proc<#randomize>`_ that uses the current time instead
- ## * `initRand proc<#initRand>`_ that initializes a Rand state using
- ## the current time
- runnableExamples:
- from std/times import getTime, toUnix, nanosecond
- randomize(123)
- let now = getTime()
- randomize(now.toUnix * 1_000_000_000 + now.nanosecond)
- state = initRand(seed)
- proc shuffle*[T](r: var Rand; x: var openArray[T]) =
- ## Shuffles a sequence of elements in-place using the given state.
- ##
- ## **See also:**
- ## * `shuffle proc<#shuffle,openArray[T]>`_ that uses the default RNG
- runnableExamples:
- var cards = ["Ace", "King", "Queen", "Jack", "Ten"]
- var r = initRand(678)
- r.shuffle(cards)
- import std/algorithm
- assert cards.sorted == @["Ace", "Jack", "King", "Queen", "Ten"]
- for i in countdown(x.high, 1):
- let j = r.rand(i)
- swap(x[i], x[j])
- proc shuffle*[T](x: var openArray[T]) =
- ## Shuffles a sequence of elements in-place.
- ##
- ## If `randomize <#randomize>`_ has not been called, the order of outcomes
- ## from this proc will always be the same.
- ##
- ## This proc uses the default RNG. Thus, it is **not** thread-safe.
- ##
- ## **See also:**
- ## * `shuffle proc<#shuffle,Rand,openArray[T]>`_ that uses a provided state
- runnableExamples:
- var cards = ["Ace", "King", "Queen", "Jack", "Ten"]
- randomize(678)
- shuffle(cards)
- import std/algorithm
- assert cards.sorted == @["Ace", "Jack", "King", "Queen", "Ten"]
- shuffle(state, x)
- when not defined(standalone):
- when defined(js):
- import std/times
- else:
- when defined(nimscript):
- import std/hashes
- else:
- import std/[hashes, os, sysrand, monotimes]
- when compileOption("threads"):
- import locks
- var baseSeedLock: Lock
- baseSeedLock.initLock
- var baseState: Rand
- proc initRand(): Rand =
- ## Initializes a new Rand state.
- ##
- ## The resulting state is independent of the default RNG's state.
- ##
- ## **Note:** Does not work for the compile-time VM.
- ##
- ## See also:
- ## * `initRand proc<#initRand,int64>`_ that accepts a seed for a new Rand state
- ## * `randomize proc<#randomize>`_ that initializes the default RNG using the current time
- ## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default RNG
- when defined(js):
- let time = int64(times.epochTime() * 1000) and 0x7fff_ffff
- result = initRand(time)
- else:
- proc getRandomState(): Rand =
- when defined(nimscript):
- result = Rand(
- a0: CompileTime.hash.Ui,
- a1: CompileDate.hash.Ui)
- if not result.isValid:
- result = DefaultRandSeed
- else:
- var urand: array[sizeof(Rand), byte]
- for i in 0 .. 7:
- if sysrand.urandom(urand):
- copyMem(result.addr, urand[0].addr, sizeof(Rand))
- if result.isValid:
- break
- if not result.isValid:
- # Don't try to get alternative random values from other source like time or process/thread id,
- # because such code would be never tested and is a liability for security.
- quit("Failed to initializes baseState in random module as sysrand.urandom doesn't work.")
- when compileOption("threads"):
- baseSeedLock.withLock:
- if not baseState.isValid:
- baseState = getRandomState()
- result = baseState
- baseState.skipRandomNumbers
- else:
- if not baseState.isValid:
- baseState = getRandomState()
- result = baseState
- baseState.skipRandomNumbers
- since (1, 5, 1):
- export initRand
- proc randomize*() {.benign.} =
- ## Initializes the default random number generator with a seed based on
- ## random number source.
- ##
- ## This proc only needs to be called once, and it should be called before
- ## the first usage of procs from this module that use the default RNG.
- ##
- ## **Note:** Does not work for the compile-time VM.
- ##
- ## **See also:**
- ## * `randomize proc<#randomize,int64>`_ that accepts a seed
- ## * `initRand proc<#initRand>`_ that initializes a Rand state using
- ## the current time
- ## * `initRand proc<#initRand,int64>`_ that initializes a Rand state
- ## with a given seed
- state = initRand()
- {.pop.}
|