diff options
Diffstat (limited to 'lib/stdlib/doc/src/rand.xml')
-rw-r--r-- | lib/stdlib/doc/src/rand.xml | 614 |
1 files changed, 483 insertions, 131 deletions
diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml index 50057259c6..21f680a0ee 100644 --- a/lib/stdlib/doc/src/rand.xml +++ b/lib/stdlib/doc/src/rand.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2015</year> + <year>2015</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,215 +33,567 @@ <file>rand.xml</file> </header> <module>rand</module> - <modulesummary>Pseudo random number generation</modulesummary> + <modulesummary>Pseudo random number generation.</modulesummary> <description> - <p>Random number generator.</p> - - <p>The module contains several different algorithms and can be - extended with more in the future. The current uniform - distribution algorithms uses the - <url href="http://xorshift.di.unimi.it"> - scrambled Xorshift algorithms by Sebastiano Vigna</url> and the - normal distribution algorithm uses the - <url href="http://www.jstatsoft.org/v05/i08"> - Ziggurat Method by Marsaglia and Tsang</url>. + <p> + This module provides a pseudo random number generator. + The module contains a number of algorithms. + The uniform distribution algorithms use the + <url href="http://xorshift.di.unimi.it"> + xoroshiro116+ and xorshift1024* algorithms by Sebastiano Vigna. + </url> + The normal distribution algorithm uses the + <url href="http://www.jstatsoft.org/v05/i08"> + Ziggurat Method by Marsaglia and Tsang + </url> + on top of the uniform distribution algorithm. </p> + <p>For some algorithms, jump functions are provided for generating + non-overlapping sequences for parallel computations. + The jump functions perform calculations + equivalent to perform a large number of repeated calls + for calculating new states. </p> + + <p>The following algorithms are provided:</p> - <p>The implemented algorithms are:</p> <taglist> - <tag><c>exsplus</c></tag> <item>Xorshift116+, 58 bits precision and period of 2^116-1.</item> - <tag><c>exs64</c></tag> <item>Xorshift64*, 64 bits precision and a period of 2^64-1.</item> - <tag><c>exs1024</c></tag> <item>Xorshift1024*, 64 bits precision and a period of 2^1024-1.</item> + <tag><c>exrop</c></tag> + <item> + <p>Xoroshiro116+, 58 bits precision and period of 2^116-1</p> + <p>Jump function: equivalent to 2^64 calls</p> + </item> + <tag><c>exs1024s</c></tag> + <item> + <p>Xorshift1024*, 64 bits precision and a period of 2^1024-1</p> + <p>Jump function: equivalent to 2^512 calls</p> + </item> + <tag><c>exsp</c></tag> + <item> + <p>Xorshift116+, 58 bits precision and period of 2^116-1</p> + <p>Jump function: equivalent to 2^64 calls</p> + <p> + This is a corrected version of the previous default algorithm, + that now has been superseded by Xoroshiro116+ (<c>exrop</c>). + Since there is no native 58 bit rotate instruction this + algorithm executes a little (say < 15%) faster than <c>exrop</c>. + See the + <url href="http://xorshift.di.unimi.it">algorithms' homepage</url>. + </p> + </item> </taglist> - <p>The current default algorithm is <c>exsplus</c>. The default - may change in future. If a specific algorithm is required make - sure to always use <seealso marker="#seed-1">seed/1</seealso> - to initialize the state. + <p> + The default algorithm is <c>exrop</c> (Xoroshiro116+). + If a specific algorithm is + required, ensure to always use <seealso marker="#seed-1"> + <c>seed/1</c></seealso> to initialize the state. </p> - <p>Every time a random number is requested, a state is used to - calculate it and a new state produced. The state can either be - implicit or it can be an explicit argument and return value. + <p> + Undocumented (old) algorithms are deprecated but still implemented + so old code relying on them will produce + the same pseudo random sequences as before. </p> + <note> + <p> + There were a number of problems in the implementation + of the now undocumented algorithms, which is why + they are deprecated. The new algorithms are a bit slower + but do not have these problems: + </p> + <p> + Uniform integer ranges had a skew in the probability distribution + that was not noticable for small ranges but for large ranges + less than the generator's precision the probability to produce + a low number could be twice the probability for a high. + </p> + <p> + Uniform integer ranges larger than or equal to the generator's + precision used a floating point fallback that only calculated + with 52 bits which is smaller than the requested range + and therefore were not all numbers in the requested range + even possible to produce. + </p> + <p> + Uniform floats had a non-uniform density so small values + i.e less than 0.5 had got smaller intervals decreasing + as the generated value approached 0.0 although still uniformly + distributed for sufficiently large subranges. The new algorithms + produces uniformly distributed floats on the form N * 2.0^(-53) + hence equally spaced. + </p> + </note> + + <p>Every time a random number is requested, a state is used to + calculate it and a new state is produced. The state can either be + implicit or be an explicit argument and return value.</p> + <p>The functions with implicit state use the process dictionary - variable <c>rand_seed</c> to remember the current state.</p> + variable <c>rand_seed</c> to remember the current state.</p> + + <p>If a process calls + <seealso marker="#uniform-0"><c>uniform/0</c></seealso>, + <seealso marker="#uniform-1"><c>uniform/1</c></seealso> or + <seealso marker="#uniform_real-0"><c>uniform_real/0</c></seealso> without + setting a seed first, <seealso marker="#seed-1"><c>seed/1</c></seealso> + is called automatically with the default algorithm and creates a + non-constant seed.</p> + + <p>The functions with explicit state never use the process dictionary.</p> + + <p><em>Examples:</em></p> + + <p>Simple use; creates and seeds the default algorithm + with a non-constant seed if not already done:</p> + + <pre> +R0 = rand:uniform(), +R1 = rand:uniform(),</pre> + + <p>Use a specified algorithm:</p> + + <pre> +_ = rand:seed(exs1024s), +R2 = rand:uniform(),</pre> - <p>If a process calls <seealso marker="#uniform-0">uniform/0</seealso> or - <seealso marker="#uniform-1">uniform/1</seealso> without - setting a seed first, <seealso marker="#seed-1">seed/1</seealso> - is called automatically with the default algorithm and creates a - non-constant seed.</p> + <p>Use a specified algorithm with a constant seed:</p> - <p>The functions with explicit state never use the process - dictionary.</p> + <pre> +_ = rand:seed(exs1024s, {123, 123534, 345345}), +R3 = rand:uniform(),</pre> + + <p>Use the functional API with a non-constant seed:</p> + + <pre> +S0 = rand:seed_s(exrop), +{R4, S1} = rand:uniform_s(S0),</pre> + + <p>Textbook basic form Box-Muller standard normal deviate</p> + + <pre> +R5 = rand:uniform_real(), +R6 = rand:uniform(), +SND0 = math:sqrt(-2 * math:log(R5)) * math:cos(math:pi() * R6)</pre> + + <p>Create a standard normal deviate:</p> + + <pre> +{SND1, S2} = rand:normal_s(S1),</pre> - <p>Examples:</p> + <p>Create a normal deviate with mean -3 and variance 0.5:</p> + + <pre> +{ND0, S3} = rand:normal_s(-3, 0.5, S2),</pre> + + <note> + <p>The builtin random number generator algorithms are not + cryptographically strong. If a cryptographically strong + random number generator is needed, use something like + <seealso marker="crypto:crypto#rand_seed-0"><c>crypto:rand_seed/0</c></seealso>. + </p> + </note> + + <p> + For all these generators the lowest bit(s) has got + a slightly less random behaviour than all other bits. + 1 bit for <c>exrop</c> (and <c>exsp</c>), + and 3 bits for <c>exs1024s</c>. + See for example the explanation in the + <url href="http://xoroshiro.di.unimi.it/xoroshiro128plus.c"> + Xoroshiro128+ + </url> + generator source code: + </p> <pre> - %% Simple usage. Creates and seeds the default algorithm - %% with a non-constant seed if not already done. - R0 = rand:uniform(), - R1 = rand:uniform(), - - %% Use a given algorithm. - _ = rand:seed(exs1024), - R2 = rand:uniform(), - - %% Use a given algorithm with a constant seed. - _ = rand:seed(exs1024, {123, 123534, 345345}), - R3 = rand:uniform(), - - %% Use the functional api with non-constant seed. - S0 = rand:seed_s(exsplus), - {R4, S1} = rand:uniform_s(S0), - - %% Create a standard normal deviate. - {SND0, S2} = rand:normal_s(S1), - </pre> - - <note><p>This random number generator is not cryptographically - strong. If a strong cryptographic random number generator is - needed, use one of functions in the - <seealso marker="crypto:crypto">crypto</seealso> - module, for example <c>crypto:strong_rand_bytes/1</c>.</p></note> +Beside passing BigCrush, this generator passes the PractRand test suite +up to (and included) 16TB, with the exception of binary rank tests, +which fail due to the lowest bit being an LFSR; all other bits pass all +tests. We suggest to use a sign test to extract a random Boolean value.</pre> + <p> + If this is a problem; to generate a boolean + use something like this: + </p> + <pre>(rand:uniform(16) > 8)</pre> + <p> + And for a general range, with <c>N = 1</c> for <c>exrop</c>, + and <c>N = 3</c> for <c>exs1024s</c>: + </p> + <pre>(((rand:uniform(Range bsl N) - 1) bsr N) + 1)</pre> + <p> + The floating point generating functions in this module + waste the lowest bits when converting from an integer + so they avoid this snag. + </p> + + </description> <datatypes> <datatype> + <name name="builtin_alg"/> + </datatype> + <datatype> <name name="alg"/> </datatype> - + <datatype> + <name name="alg_handler"/> + </datatype> + <datatype> + <name name="alg_state"/> + </datatype> <datatype> <name name="state"/> - <desc><p>Algorithm dependent state.</p></desc> + <desc><p>Algorithm-dependent state.</p></desc> </datatype> - <datatype> <name name="export_state"/> - <desc><p>Algorithm dependent state which can be printed or saved to file.</p></desc> + <desc> + <p> + Algorithm-dependent state that can be printed or saved to file. + </p> + </desc> + </datatype> + <datatype> + <name name="exs64_state"/> + <desc><p>Algorithm specific internal state</p></desc> + </datatype> + <datatype> + <name name="exsplus_state"/> + <desc><p>Algorithm specific internal state</p></desc> + </datatype> + <datatype> + <name name="exs1024_state"/> + <desc><p>Algorithm specific internal state</p></desc> + </datatype> + <datatype> + <name name="exrop_state"/> + <desc><p>Algorithm specific internal state</p></desc> </datatype> </datatypes> <funcs> <func> - <name name="seed" arity="1"/> - <fsummary>Seed random number generator</fsummary> + <name name="export_seed" arity="0"/> + <fsummary>Export the random number generation state.</fsummary> + <desc><marker id="export_seed-0"/> + <p>Returns the random number state in an external format. + To be used with <seealso marker="#seed-1"><c>seed/1</c></seealso>.</p> + </desc> + </func> + + <func> + <name name="export_seed_s" arity="1"/> + <fsummary>Export the random number generation state.</fsummary> + <desc><marker id="export_seed_s-1"/> + <p>Returns the random number generator state in an external format. + To be used with <seealso marker="#seed-1"><c>seed/1</c></seealso>.</p> + </desc> + </func> + + <func> + <name name="jump" arity="0"/> + <fsummary>Return the seed after performing jump calculation + to the state in the process dictionary.</fsummary> + <desc><marker id="jump-0" /> + <p>Returns the state + after performing jump calculation + to the state in the process dictionary.</p> + <p>This function generates a <c>not_implemented</c> error exception + when the jump function is not implemented for + the algorithm specified in the state + in the process dictionary.</p> + </desc> + </func> + + <func> + <name name="jump" arity="1"/> + <fsummary>Return the seed after performing jump calculation.</fsummary> + <desc><marker id="jump-1" /> + <p>Returns the state after performing jump calculation + to the given state. </p> + <p>This function generates a <c>not_implemented</c> error exception + when the jump function is not implemented for + the algorithm specified in the state.</p> + </desc> + </func> + + <func> + <name name="normal" arity="0"/> + <fsummary>Return a standard normal distributed random float.</fsummary> <desc> - <marker id="seed-1"/> - <p>Seeds random number generation with the given algorithm and time dependent - data if <anno>AlgOrExpState</anno> is an algorithm.</p> - <p>Otherwise recreates the exported seed in the process - dictionary, and returns the state. - <em>See also:</em> <seealso marker="#export_seed-0">export_seed/0</seealso>.</p> + <p>Returns a standard normal deviate float (that is, the mean + is 0 and the standard deviation is 1) and updates the state in + the process dictionary.</p> </desc> </func> + <func> - <name name="seed_s" arity="1"/> - <fsummary>Seed random number generator</fsummary> + <name name="normal" arity="2"/> + <fsummary>Return a normal distributed random float.</fsummary> <desc> - <p>Seeds random number generation with the given algorithm and time dependent - data if <anno>AlgOrExpState</anno> is an algorithm.</p> - <p>Otherwise recreates the exported seed and returns the state. - <em>See also:</em> <seealso marker="#export_seed-0">export_seed/0</seealso>.</p> + <p>Returns a normal N(Mean, Variance) deviate float + and updates the state in the process dictionary.</p> </desc> </func> + <func> - <name name="seed" arity="2"/> - <fsummary>Seed the random number generation</fsummary> + <name name="normal_s" arity="1"/> + <fsummary>Return a standard normal distributed random float.</fsummary> <desc> - <p>Seeds random number generation with the given algorithm and - integers in the process dictionary and returns - the state.</p> + <p>Returns, for a specified state, a standard normal + deviate float (that is, the mean is 0 and the standard + deviation is 1) and a new state.</p> </desc> </func> + <func> - <name name="seed_s" arity="2"/> - <fsummary>Seed the random number generation</fsummary> + <name name="normal_s" arity="3"/> + <fsummary>Return a normal distributed random float.</fsummary> <desc> - <p>Seeds random number generation with the given algorithm and - integers and returns the state.</p> + <p>Returns, for a specified state, a normal N(Mean, Variance) + deviate float and a new state.</p> </desc> </func> <func> - <name name="export_seed" arity="0"/> - <fsummary>Export the random number generation state</fsummary> - <desc><marker id="export_seed-0"/> - <p>Returns the random number state in an external format. - To be used with <seealso marker="#seed-1">seed/1</seealso>.</p> + <name name="seed" arity="1"/> + <fsummary>Seed random number generator.</fsummary> + <desc> + <marker id="seed-1"/> + <p> + Seeds random number generation with the specifed algorithm and + time-dependent data if <c><anno>AlgOrStateOrExpState</anno></c> + is an algorithm. + </p> + <p>Otherwise recreates the exported seed in the process dictionary, + and returns the state. See also + <seealso marker="#export_seed-0"><c>export_seed/0</c></seealso>.</p> </desc> </func> <func> - <name name="export_seed_s" arity="1"/> - <fsummary>Export the random number generation state</fsummary> - <desc><marker id="export_seed_s-1"/> - <p>Returns the random number generator state in an external format. - To be used with <seealso marker="#seed-1">seed/1</seealso>.</p> + <name name="seed" arity="2"/> + <fsummary>Seed the random number generation.</fsummary> + <desc> + <p>Seeds random number generation with the specified algorithm and + integers in the process dictionary and returns the state.</p> </desc> </func> <func> - <name name="uniform" arity="0"/> - <fsummary>Return a random float</fsummary> + <name name="seed_s" arity="1"/> + <fsummary>Seed random number generator.</fsummary> <desc> - <marker id="uniform-0"/> - <p>Returns a random float uniformly distributed in the value - range <c>0.0 < <anno>X</anno> < 1.0 </c> and - updates the state in the process dictionary.</p> + <p> + Seeds random number generation with the specifed algorithm and + time-dependent data if <c><anno>AlgOrStateOrExpState</anno></c> + is an algorithm. + </p> + <p>Otherwise recreates the exported seed and returns the state. + See also <seealso marker="#export_seed-0"> + <c>export_seed/0</c></seealso>.</p> </desc> </func> + <func> - <name name="uniform_s" arity="1"/> - <fsummary>Return a random float</fsummary> + <name name="seed_s" arity="2"/> + <fsummary>Seed the random number generation.</fsummary> <desc> - <p>Given a state, <c>uniform_s/1</c> returns a random float - uniformly distributed in the value range <c>0.0 < - <anno>X</anno> < 1.0</c> and a new state.</p> + <p>Seeds random number generation with the specified algorithm and + integers and returns the state.</p> + </desc> + </func> + + <func> + <name name="uniform" arity="0"/> + <fsummary>Return a random float.</fsummary> + <desc><marker id="uniform-0"/> + <p> + Returns a random float uniformly distributed in the value + range <c>0.0 =< <anno>X</anno> < 1.0</c> and + updates the state in the process dictionary. + </p> + <p> + The generated numbers are on the form N * 2.0^(-53), + that is; equally spaced in the interval. + </p> + <warning> + <p> + This function may return exactly <c>0.0</c> which can be + fatal for certain applications. If that is undesired + you can use <c>(1.0 - rand:uniform())</c> to get the + interval <c>0.0 < <anno>X</anno> =< 1.0</c>, or instead use + <seealso marker="#uniform_real-0"><c>uniform_real/0</c></seealso>. + </p> + <p> + If neither endpoint is desired you can test and re-try + like this: + </p> + <pre> +my_uniform() -> + case rand:uniform() of + 0.0 -> my_uniform(); + X -> X + end +end.</pre> + </warning> + </desc> + </func> + + <func> + <name name="uniform_real" arity="0"/> + <fsummary>Return a random float.</fsummary> + <desc><marker id="uniform_real-0"/> + <p> + Returns a random float + uniformly distributed in the value range + <c>DBL_MIN =< <anno>X</anno> < 1.0</c> + and updates the state in the process dictionary. + </p> + <p> + Conceptually, a random real number <c>R</c> is generated + from the interval <c>0 =< R < 1</c> and then the + closest rounded down normalized number + in the IEEE 754 Double precision format + is returned. + </p> + <note> + <p> + The generated numbers from this function has got better + granularity for small numbers than the regular + <seealso marker="#uniform-0"><c>uniform/0</c></seealso> + because all bits in the mantissa are random. + This property, in combination with the fact that exactly zero + is never returned is useful for algoritms doing for example + <c>1.0 / <anno>X</anno></c> or <c>math:log(<anno>X</anno>)</c>. + </p> + </note> + <p> + See + <seealso marker="#uniform_real_s-1"><c>uniform_real_s/1</c></seealso> + for more explanation. + </p> </desc> </func> <func> <name name="uniform" arity="1"/> - <fsummary>Return a random integer</fsummary> - <desc> - <marker id="uniform-1"/> - <p>Given an integer <c><anno>N</anno> >= 1</c>, - <c>uniform/1</c> returns a random integer uniformly - distributed in the value range - <c>1 <= <anno>X</anno> <= <anno>N</anno></c> and - updates the state in the process dictionary.</p> + <fsummary>Return a random integer.</fsummary> + <desc><marker id="uniform-1"/> + <p>Returns, for a specified integer <c><anno>N</anno> >= 1</c>, + a random integer uniformly distributed in the value range + <c>1 =< <anno>X</anno> =< <anno>N</anno></c> and + updates the state in the process dictionary.</p> </desc> </func> + <func> - <name name="uniform_s" arity="2"/> - <fsummary>Return a random integer</fsummary> + <name name="uniform_s" arity="1"/> + <fsummary>Return a random float.</fsummary> <desc> - <p>Given an integer <c><anno>N</anno> >= 1</c> and a state, - <c>uniform_s/2</c> returns a random integer uniformly - distributed in the value range <c>1 <= <anno>X</anno> <= - <anno>N</anno></c> and a new state.</p> + <p> + Returns, for a specified state, random float + uniformly distributed in the value range <c>0.0 =< + <anno>X</anno> < 1.0</c> and a new state. + </p> + <p> + The generated numbers are on the form N * 2.0^(-53), + that is; equally spaced in the interval. + </p> + <warning> + <p> + This function may return exactly <c>0.0</c> which can be + fatal for certain applications. If that is undesired + you can use <c>(1.0 - rand:uniform(State))</c> to get the + interval <c>0.0 < <anno>X</anno> =< 1.0</c>, or instead use + <seealso marker="#uniform_real_s-1"><c>uniform_real_s/1</c></seealso>. + </p> + <p> + If neither endpoint is desired you can test and re-try + like this: + </p> + <pre> +my_uniform(State) -> + case rand:uniform(State) of + {0.0, NewState} -> my_uniform(NewState); + Result -> Result + end +end.</pre> + </warning> </desc> </func> <func> - <name name="normal" arity="0"/> - <fsummary>Return a standard normal distributed random float</fsummary> + <name name="uniform_real_s" arity="1"/> + <fsummary>Return a random float.</fsummary> <desc> - <p>Returns a standard normal deviate float (that is, the mean - is 0 and the standard deviation is 1) and updates the state in - the process dictionary.</p> + <p> + Returns, for a specified state, a random float + uniformly distributed in the value range + <c>DBL_MIN =< <anno>X</anno> < 1.0</c> + and updates the state in the process dictionary. + </p> + <p> + Conceptually, a random real number <c>R</c> is generated + from the interval <c>0 =< R < 1</c> and then the + closest rounded down normalized number + in the IEEE 754 Double precision format + is returned. + </p> + <note> + <p> + The generated numbers from this function has got better + granularity for small numbers than the regular + <seealso marker="#uniform_s-1"><c>uniform_s/1</c></seealso> + because all bits in the mantissa are random. + This property, in combination with the fact that exactly zero + is never returned is useful for algoritms doing for example + <c>1.0 / <anno>X</anno></c> or <c>math:log(<anno>X</anno>)</c>. + </p> + </note> + <p> + The concept implicates that the probability to get + exactly zero is extremely low; so low that this function + is in fact guaranteed to never return zero. The smallest + number that it might return is <c>DBL_MIN</c>, which is + 2.0^(-1022). + </p> + <p> + The value range stated at the top of this function + description is technically correct, but + <c>0.0 =< <anno>X</anno> < 1.0</c> + is a better description of the generated numbers' + statistical distribution. Except that exactly 0.0 + is never returned, which is not possible to observe + statistically. + </p> + <p> + For example; for all sub ranges + <c>N*2.0^(-53) =< X < (N+1)*2.0^(-53)</c> + where + <c>0 =< integer(N) < 2.0^53</c> + the probability is the same. + Compare that with the form of the numbers generated by + <seealso marker="#uniform_s-1"><c>uniform_s/1</c></seealso>. + </p> + <p> + Having to generate extra random bits for + small numbers costs a little performance. + This function is about 20% slower than the regular + <seealso marker="#uniform_s-1"><c>uniform_s/1</c></seealso> + </p> </desc> </func> + <func> - <name name="normal_s" arity="1"/> - <fsummary>Return a standard normal distributed random float</fsummary> + <name name="uniform_s" arity="2"/> + <fsummary>Return a random integer.</fsummary> <desc> - <p>Given a state, <c>normal_s/1</c> returns a standard normal - deviate float (that is, the mean is 0 and the standard - deviation is 1) and a new state.</p> + <p>Returns, for a specified integer <c><anno>N</anno> >= 1</c> + and a state, a random integer uniformly distributed in the value + range <c>1 =< <anno>X</anno> =< <anno>N</anno></c> and a + new state.</p> </desc> </func> - </funcs> </erlref> |