summary refs log tree commit diff stats
path: root/lib/pure/random.nim
diff options
context:
space:
mode:
authorJjp137 <Jjp137@users.noreply.github.com>2019-02-10 23:50:31 -0800
committerAndreas Rumpf <rumpf_a@web.de>2019-02-13 23:30:14 +0100
commit7bb94abc31c7406dd8b6119f9d63375830de5fb0 (patch)
treef045f943d439a032307b12e303eaaa3dc185edab /lib/pure/random.nim
parent0ebef1764d21dbd7ad05af0b3d00c78b0628f4fa (diff)
downloadNim-7bb94abc31c7406dd8b6119f9d63375830de5fb0.tar.gz
better docs: random (#10546)
Diffstat (limited to 'lib/pure/random.nim')
-rw-r--r--lib/pure/random.nim489
1 files changed, 423 insertions, 66 deletions
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index 378ca6f87..85466ed9e 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -7,12 +7,76 @@
 #    distribution, for details about the copyright.
 #
 
-## Nim's standard random number generator. Based on
-## the ``xoroshiro128+`` (xor/rotate/shift/rotate) library.
+## Nim's standard random number generator.
+##
+## 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
+## ===========
+##
+## To get started, here are some examples:
+##
+## .. code-block::
+##
+##   import random
+##
+##   # 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 between 0 and 100
+##   let num = rand(100)
+##   echo num
+##
+##   # Roll a six-sided die
+##   let roll = rand(1..6)
+##   echo roll
+##
+##   # Pick a marble from a bag
+##   let marbles = ["red", "blue", "green", "yellow", "purple"]
+##   let pick = sample(marbles)
+##   echo pick
+##
+##   # Shuffle some cards
+##   var cards = ["Ace", "King", "Queen", "Jack", "Ten"]
+##   shuffle(cards)
+##   echo cards
+##
+## These examples all use the default random number generator. The
+## `Rand type<#Rand>`_ represents the state of a random number generator.
+## For convenience, this module contains a default Rand state that corresponds
+## to the default random number generator. 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, then the default generator will always produce
+## the same results.
+##
+## Generators 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
+## ========
+## * `math module<math.html>`_ for basic math routines
+## * `mersenne module<mersenne.html>`_ for the Mersenne Twister random number
+##   generator
+## * `stats module<stats.html>`_ for statistical analysis
+## * `list of cryptographic and hashing modules
+##   <lib.html#pure-libraries-cryptography-and-hashing>`_
+##   in the standard library
 
 import algorithm                    #For upperBound
 
@@ -29,9 +93,19 @@ else:
   const randMax = 18_446_744_073_709_551_615u64
 
 type
-  Rand* = object ## State of the random number generator.
-                 ## The procs that use the default state
-                 ## are **not** thread-safe!
+  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 random number generator'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):
@@ -48,7 +122,20 @@ proc rotl(x, k: ui): ui =
   result = (x shl k) or (x shr (ui(64) - k))
 
 proc next*(r: var Rand): uint64 =
-  ## Uses the state to compute a new ``uint64`` random number.
+  ## 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,T]>`_ that accepts a slice
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `skipRandomNumbers proc<#skipRandomNumbers,Rand>`_
+  runnableExamples:
+    var r = initRand(2019)
+    doAssert r.next() == 138_744_656_611_299'u64
+    doAssert r.next() == 979_810_537_855_049_344'u64
+    doAssert r.next() == 3_628_232_584_225_300_704'u64
   let s0 = r.a0
   var s1 = r.a1
   result = s0 + s1
@@ -57,9 +144,52 @@ proc next*(r: var Rand): uint64 =
   r.a1 = rotl(s1, 36) # c
 
 proc skipRandomNumbers*(s: var Rand) =
-  ## This is the jump function for the generator. It is equivalent
-  ## to 2^64 calls to next(); it can be used to generate 2^64
-  ## non-overlapping subsequences for parallel computations.
+  ## 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.
+  ##
+  ## The following example below demonstrates this pattern:
+  ##
+  ## .. code-block::
+  ##   # Compile this example with --threads:on
+  ##   import random
+  ##   import threadpool
+  ##
+  ##   const spawns = 4
+  ##   const numbers = 100000
+  ##
+  ##   proc randomSum(rand: Rand): int =
+  ##     var r = rand
+  ##     for i in 1..numbers:
+  ##       result += rand(1..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:
+  ##     echo ^val
+  ##
+  ## See also:
+  ## * `next proc<#next,Rand>`_
   when defined(JS):
     const helper = [0xbeac0467u32, 0xd86b048bu32]
   else:
@@ -77,22 +207,16 @@ proc skipRandomNumbers*(s: var Rand) =
   s.a1 = s1
 
 proc random*(max: int): int {.benign, deprecated.} =
-  ## Returns a random number in the range 0..max-1. The sequence of
-  ## random number is always the same, unless `randomize` is called
-  ## which initializes the random number generator with a "random"
-  ## number, i.e. a tickcount. **Deprecated since version 0.18.0**.
-  ## Use ``rand`` instead.
+  ## **Deprecated since version 0.18.0:**
+  ## Use `rand(int)<#rand,int>`_ instead.
   while true:
     let x = next(state)
     if x < randMax - (randMax mod ui(max)):
       return int(x mod uint64(max))
 
 proc random*(max: float): float {.benign, deprecated.} =
-  ## Returns a random number in the range 0..<max. The sequence of
-  ## random number is always the same, unless `randomize` is called
-  ## which initializes the random number generator with a "random"
-  ## number, i.e. a tickcount. **Deprecated since version 0.18.0**.
-  ## Use ``rand`` instead.
+  ## **Deprecated since version 0.18.0:**
+  ## Use `rand(float)<#rand,float>`_ instead.
   let x = next(state)
   when defined(JS):
     result = (float(x) / float(high(uint32))) * max
@@ -101,22 +225,29 @@ proc random*(max: float): float {.benign, deprecated.} =
     result = (cast[float](u) - 1.0) * max
 
 proc random*[T](x: HSlice[T, T]): T {.deprecated.} =
-  ## For a slice `a .. b` returns a value in the range `a .. b-1`.
-  ## **Deprecated since version 0.18.0**.
-  ## Use ``rand`` instead.
+  ## **Deprecated since version 0.18.0:**
+  ## Use `rand[T](HSlice[T, T])<#rand,HSlice[T,T]>`_ instead.
   result = T(random(x.b - x.a)) + x.a
 
 proc random*[T](a: openArray[T]): T {.deprecated.} =
-  ## returns a random element from the openarray `a`.
-  ## **Deprecated since version 0.18.0**.
-  ## Use ``rand`` instead.
+  ## **Deprecated since version 0.18.0:**
+  ## Use `sample[T](openArray[T])<#sample,openArray[T]>`_ instead.
   result = a[random(a.low..a.len)]
 
 proc rand*(r: var Rand; max: Natural): int {.benign.} =
-  ## Returns a random number in the range 0..max. The sequence of
-  ## random number is always the same, unless `randomize` is called
-  ## which initializes the random number generator with a "random"
-  ## number, i.e. a tickcount.
+  ## 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
+  ##   random number generator
+  ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
+  ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  runnableExamples:
+    var r = initRand(123)
+    doAssert r.rand(100) == 0
+    doAssert r.rand(100) == 96
+    doAssert r.rand(100) == 66
   if max == 0: return
   while true:
     let x = next(r)
@@ -124,17 +255,41 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} =
       return int(x mod (uint64(max)+1u64))
 
 proc rand*(max: int): int {.benign.} =
-  ## Returns a random number in the range 0..max. The sequence of
-  ## random number is always the same, unless `randomize` is called
-  ## which initializes the random number generator with a "random"
-  ## number, i.e. a tickcount.
+  ## 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 random number generator. 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,T]>`_ that accepts a slice
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  runnableExamples:
+    randomize(123)
+    doAssert rand(100) == 0
+    doAssert rand(100) == 96
+    doAssert rand(100) == 66
   rand(state, max)
 
 proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} =
-  ## Returns a random number in the range 0..max. The sequence of
-  ## random number is always the same, unless `randomize` is called
-  ## which initializes the random number generator with a "random"
-  ## number, i.e. a tickcount.
+  ## 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
+  ##   random number generator
+  ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
+  ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  runnableExamples:
+    var r = initRand(234)
+    let f = r.rand(1.0)
+    ## f = 8.717181376738381e-07
   let x = next(r)
   when defined(JS):
     result = (float(x) / float(high(uint32))) * max
@@ -143,51 +298,162 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} =
     result = (cast[float](u) - 1.0) * max
 
 proc rand*(max: float): float {.benign.} =
-  ## Returns a random number in the range 0..max. The sequence of
-  ## random number is always the same, unless `randomize` is called
-  ## which initializes the random number generator with a "random"
-  ## number, i.e. a tickcount.
+  ## 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 random number generator. 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,T]>`_ that accepts a slice
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  runnableExamples:
+    randomize(234)
+    let f = rand(1.0)
+    ## f = 8.717181376738381e-07
   rand(state, max)
 
 proc rand*[T](r: var Rand; x: HSlice[T, T]): T =
-  ## For a slice `a .. b` returns a value in the range `a .. b`.
+  ## For a slice `a..b`, returns a value in the range `a..b` using the given
+  ## state.
+  ##
+  ## See also:
+  ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice and uses the
+  ##   default random number generator
+  ## * `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 type
+  runnableExamples:
+    var r = initRand(345)
+    doAssert r.rand(1..6) == 4
+    doAssert r.rand(1..6) == 4
+    doAssert r.rand(1..6) == 6
   result = T(rand(r, x.b - x.a)) + x.a
 
 proc rand*[T](x: HSlice[T, T]): T =
-  ## For a slice `a .. b` returns a value in the range `a .. b`.
+  ## For a slice `a..b`, returns a value in the range `a..b`.
+  ##
+  ## 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 random number generator. Thus, it is **not**
+  ## thread-safe.
+  ##
+  ## See also:
+  ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ 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 type
+  runnableExamples:
+    randomize(345)
+    doAssert rand(1..6) == 4
+    doAssert rand(1..6) == 4
+    doAssert rand(1..6) == 6
   result = rand(state, x)
 
 proc rand*[T](r: var Rand; a: openArray[T]): T {.deprecated.} =
-  ## Returns a random element from the openarray `a`.
-  ## **Deprecated since v0.20.0:** use ``sample`` instead.
+  ## **Deprecated since version 0.20.0:**
+  ## Use `sample[T](Rand, openArray[T])<#sample,Rand,openArray[T]>`_ instead.
   result = a[rand(r, a.low..a.high)]
 
 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 random number generator. 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,T]>`_ that accepts a slice
+  runnableExamples:
+    randomize(567)
+    doAssert rand(int8) == 55
+    doAssert rand(int8) == -42
+    doAssert rand(int8) == 43
+    doAssert rand(uint32) == 578980729'u32
+    doAssert rand(uint32) == 4052940463'u32
+    doAssert rand(uint32) == 2163872389'u32
   result = cast[T](state.next)
 
 proc rand*[T](a: openArray[T]): T {.deprecated.} =
-  ## returns a random element from the openarray `a`.
-  ## **Deprecated since v0.20.0:** use ``sample`` instead.
+  ## **Deprecated since version 0.20.0:**
+  ## Use `sample[T](openArray[T])<#sample,openArray[T]>`_ instead.
   result = a[rand(a.low..a.high)]
 
 proc sample*[T](r: var Rand; a: openArray[T]): T =
-  ## returns a random element from openArray ``a`` using state in ``r``.
+  ## Returns a random element from ``a`` using the given state.
+  ##
+  ## See also:
+  ## * `sample proc<#sample,openArray[T]>`_ that uses the default
+  ##   random number generator
+  ## * `sample proc<#sample,Rand,openArray[T],openArray[U]>`_ that uses a
+  ##   cumulative distribution function
+  runnableExamples:
+    let marbles = ["red", "blue", "green", "yellow", "purple"]
+    var r = initRand(456)
+    doAssert r.sample(marbles) == "blue"
+    doAssert r.sample(marbles) == "yellow"
+    doAssert r.sample(marbles) == "red"
   result = a[r.rand(a.low..a.high)]
 
 proc sample*[T](a: openArray[T]): T =
-  ## returns a random element from openArray ``a`` using non-thread-safe state.
+  ## 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 random number generator. 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
+  runnableExamples:
+    let marbles = ["red", "blue", "green", "yellow", "purple"]
+    randomize(456)
+    doAssert sample(marbles) == "blue"
+    doAssert sample(marbles) == "yellow"
+    doAssert sample(marbles) == "red"
   result = a[rand(a.low..a.high)]
 
 proc sample*[T, U](r: var Rand; a: openArray[T], cdf: openArray[U]): T =
-  ## Sample one element from openArray ``a`` when it has cumulative distribution
-  ## function (CDF) ``cdf`` (not necessarily normalized, any type of elements
-  ## convertible to ``float``). Uses state in ``r``. E.g.:
-  ##
-  ## .. code-block:: nim
-  ##   let val = [ "a", "b", "c", "d" ]  # some values
-  ##   var cnt = [1, 2, 3, 4]            # histogram of counts
-  ##   echo r.sample(val, cnt.cumsummed) # echo a sample
+  ## 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 random number generator
+  ## * `sample proc<#sample,Rand,openArray[T]>`_ that does not use a CDF
+  runnableExamples:
+    from 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)
+    doAssert r.sample(marbles, cdf) == "red"
+    doAssert r.sample(marbles, cdf) == "green"
+    doAssert r.sample(marbles, cdf) == "blue"
   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
@@ -196,37 +462,128 @@ proc sample*[T, U](r: var Rand; a: openArray[T], cdf: openArray[U]): T =
   a[cdf.upperBound(U(u))]
 
 proc sample*[T, U](a: openArray[T], cdf: openArray[U]): T =
-  ## Like ``sample(var Rand; openArray[T], openArray[U])``, but uses default
-  ## non-thread-safe state.
+  ## Returns an element from ``a`` using a cumulative distribution function
+  ## (CDF).
+  ##
+  ## This proc works similarly to
+  ## `sample[T, U](Rand, openArray[T], openArray[U])
+  ## <#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 random number generator. 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
+  runnableExamples:
+    from math import cumsummed
+
+    let marbles = ["red", "blue", "green", "yellow", "purple"]
+    let count = [1, 6, 8, 3, 4]
+    let cdf = count.cumsummed
+    randomize(789)
+    doAssert sample(marbles, cdf) == "red"
+    doAssert sample(marbles, cdf) == "green"
+    doAssert sample(marbles, cdf) == "blue"
   state.sample(a, cdf)
 
 proc initRand*(seed: int64): Rand =
-  ## Creates a new ``Rand`` state from ``seed``.
+  ## Initializes a new `Rand<#Rand>`_ state using the given seed.
+  ##
+  ## `seed` must not be zero. Providing a specific seed will produce
+  ## the same results for that seed each time.
+  ##
+  ## The resulting state is independent of the default random number
+  ## generator's state.
+  ##
+  ## See also:
+  ## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default
+  ##   random number generator
+  ## * `randomize proc<#randomize>`_ that initializes the default random
+  ##   number generator using the current time
+  runnableExamples:
+    from times import getTime, toUnix, nanosecond
+
+    var r1 = initRand(123)
+
+    let now = getTime()
+    var r2 = initRand(now.toUnix * 1_000_000_000 + now.nanosecond)
   result.a0 = ui(seed shr 16)
   result.a1 = ui(seed and 0xffff)
   discard next(result)
 
 proc randomize*(seed: int64) {.benign.} =
-  ## Initializes the default random number generator
-  ## with a specific seed.
+  ## Initializes the default random number generator with the given seed.
+  ##
+  ## `seed` must not be zero. Providing a specific seed will produce
+  ## the same results for that seed each time.
+  ##
+  ## See also:
+  ## * `initRand proc<#initRand,int64>`_
+  ## * `randomize proc<#randomize>`_ that uses the current time instead
+  runnableExamples:
+    from 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]) =
-  ## Swaps the positions of elements in a sequence randomly.
+  ## Shuffles a sequence of elements in-place using the given state.
+  ##
+  ## See also:
+  ## * `shuffle proc<#shuffle,openArray[T]>`_ that uses the default
+  ##   random number generator
+  runnableExamples:
+    var cards = ["Ace", "King", "Queen", "Jack", "Ten"]
+    var r = initRand(678)
+    r.shuffle(cards)
+    doAssert cards == ["King", "Ace", "Queen", "Ten", "Jack"]
   for i in countdown(x.high, 1):
     let j = r.rand(i)
     swap(x[i], x[j])
 
 proc shuffle*[T](x: var openArray[T]) =
-  ## Swaps the positions of elements in a sequence randomly.
+  ## 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 random number generator. 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)
+    doAssert cards == ["King", "Ace", "Queen", "Ten", "Jack"]
   shuffle(state, x)
 
 when not defined(nimscript):
   import times
 
   proc randomize*() {.benign.} =
-    ## Initializes the random number generator with a "random"
-    ## number, i.e. a tickcount. Note: Does not work for NimScript.
+    ## Initializes the default random number generator with a value based on
+    ## the current time.
+    ##
+    ## 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 random
+    ## number generator.
+    ##
+    ## **Note:** Does not work for NimScript.
+    ##
+    ## See also:
+    ## * `randomize proc<#randomize,int64>`_ that accepts a seed
+    ## * `initRand proc<#initRand,int64>`_
     when defined(js):
       let time = int64(times.epochTime() * 1_000_000_000)
       randomize(time)