@@ -40,14 +40,17 @@ PRNGs in general, and so the algorithms in this module, are mostly used
4040for test and simulation. They are designed for good statistical
4141quality and high generation speed.
4242
43- An generator algorithm, for each iteration, takes a state as input
43+ A generator algorithm, for each iteration, takes a state as input
4444and produces a raw pseudo random number and a new state to be used
4545for the next iteration.
4646
4747A particular state always produces the same number and new state.
4848The initial state is produced from a [seed](`seed/1`).
4949This makes it possible to repeat for example a simulation with the same
5050random number sequence, by re-using the same seed.
51+ There are also the functions `export_seed/0` and `export_seed_s/1`
52+ that capture the PRNG state in an `t:export_state/0`,
53+ that can be used to start from a known state.
5154
5255This property, and others, make the algorithms in this module
5356unsuitable for cryptographical applications, but in the `m:crypto` module
@@ -56,19 +59,19 @@ there are suitable generators, for this module's
5659See `crypto:rand_seed_s/0` and `crypto:rand_seed_alg_s/1`.
5760
5861At the end of this module documentation there are some
59- [niche algorithms](#niche-algorithms) that does not use
62+ [niche algorithms](#niche-algorithms) that do not use
6063this module's normal [plug-in framework](#plug-in-framework).
61- They may be useful for special purposes like fast generation
64+ They are useful for special purposes like fast generation
6265when quality is not essential, for seeding other generators, and such.
6366
6467[](){: #plug-in-framework } Plug-in framework
6568---------------------------------------------
6669
6770The raw pseudo random numbers produced by the base generators
68- are only suitable in some cases such as power of two ranges
71+ are only appropriate in some cases such as power of two ranges
6972less than the generator size, and some have quirks,
7073for example weak low bits. Therefore, the Plug-in Framework
71- implements a common [API](#plug-in-framework-api) to all base generator ,
74+ implements a common [API](#plug-in-framework-api) for all base generators ,
7275that add essential or useful funcionality:
7376
7477* Keeping the generator [state](`seed/1`) in the process dictionary.
@@ -93,7 +96,7 @@ A generator has to be initialized. This is done by one of the
9396`seed/1` or `seed_s/1` functions, which also select which
9497[algorithm](#algorithms) to use. The `seed/1` functions
9598store the generator and state in the process dictionary,
96- while the `seed_s/1` functions do not , which requires
99+ while the `seed_s/1` functions only return the state , which requires
97100the calling code to handle the state and updates to it.
98101
99102The seed functions that do not have a `Seed` value as an argument
@@ -113,7 +116,8 @@ Sibling functions without that suffix take an implicit state from
113116and store the new state in the process dictionary, and only return
114117their "interesting " output value. If the process dictionary
115118does not contain a state, [`seed(default)`](`seed/1`)
116- is implicitly called to create an automatic seed as initial state.
119+ is implicitly called to create an automatic seed for the
120+ [_default algorithm_](#default-algorithm) as initial state.
117121
118122#### _Usage_
119123
@@ -123,7 +127,7 @@ functions, which also selects a PRNG algorithm.
123127Then call a [Plug-in framework API](#plug-in-framework-api) function
124128either with an explicit state from the seed function
125129and use the returned new state in the next call,
126- or call an API function without an explicit state
130+ or call an API function without an explicit state argument
127131to operate on the state in the process dictionary.
128132
129133#### _Examples_
@@ -132,7 +136,7 @@ to operate on the state in the process dictionary.
132136%% Generate two uniformly distibuted floating point numbers.
133137%%
134138%% By not calling a [seed](`seed/1`) function, this uses
135- %% the genarator state and algorithm in the process dictinary .
139+ %% the generator state and algorithm in the process dictionary .
136140%% If there is no state there, [`seed(default)`](`seed/1`)
137141%% is implicitly called first:
138142%%
159163%% with an automatic default seed, then generate
160164%% a floating point number:
161165%%
162- 5> _ = rand:seed(exro928ss).
166+ 5> rand:seed(exro928ss).
1631676> R2 = rand:uniform(),
164168 is_float(R2) andalso 0.0 =< R2 andalso R2 < 1.0.
165169true
@@ -168,12 +172,11 @@ true
168172%% with a specified seed, then generate
169173%% a floating point number:
170174%%
171- 7> _ = rand:seed(exro928ss, 123456789).
172- 8> R3 = rand:uniform(),
173- is_float(R3) andalso 0.0 =< R3 andalso R3 < 1.0.
174- true
175+ 7> rand:seed(exro928ss, 123456789).
176+ 8> R3 = rand:uniform().
177+ 0.48303622772415256
175178
176- %% Select and initialize a specified algorithm,
179+ %% Select and initialize a specific algorithm,
177180%% with an automatic default seed, using the functional API
178181%% with explicit generator state, then generate
179182%% two floating point numbers.
196199true
197200
198201%% Generate a normal distribution number
199- %% with with mean -3 and variance 0.5:
202+ %% with mean -3 and variance 0.5:
200203%%
20120414> {ND0, S4} = rand:normal_s(-3, 0.5, S3),
202205 is_float(ND0).
@@ -236,9 +239,10 @@ per generator bit.
236239
237240By using a jump function instead of starting several generators
238241from different seeds it is assured that the generated sequences
239- does not overlap. Two different seeds may accidentally start
240- the generators in sequence positions that are close to each other,
241- but a jump function jumps to a sequence position very far ahead.
242+ do not overlap. The alternative of using different seeds
243+ may accidentally start the generators in sequence positions
244+ that are close to each other, but a jump function jumps
245+ to a sequence position very far ahead.
242246
243247To create numbers with normal distribution the
244248[Ziggurat Method by Marsaglia and Tsang](http://www.jstatsoft.org/v05/i08)
@@ -248,9 +252,9 @@ The following algorithms are provided:
248252
249253- **`exsss`**, the [_default algorithm_](#default-algorithm)
250254 *(Since OTP 22.0)*
251- Xorshift116\*\*, 58 bits precision and period of 2^116-1
255+ Xorshift116\*\*, 58 bits precision and period of 2^116-1.
252256
253- Jump function: equivalent to 2^64 calls
257+ Jump function: equivalent to 2^64 calls.
254258
255259 This is the Xorshift116 generator combined with the StarStar scrambler from
256260 the 2018 paper by David Blackman and Sebastiano Vigna:
@@ -265,9 +269,9 @@ The following algorithms are provided:
265269 its statistical qualities.
266270
267271- **`exro928ss`** *(Since OTP 22.0)*
268- Xoroshiro928\*\*, 58 bits precision and a period of 2^928-1
272+ Xoroshiro928\*\*, 58 bits precision and a period of 2^928-1.
269273
270- Jump function: equivalent to 2^512 calls
274+ Jump function: equivalent to 2^512 calls.
271275
272276 This is a 58 bit version of Xoroshiro1024\*\*, from the 2018 paper by
273277 David Blackman and Sebastiano Vigna:
@@ -280,25 +284,29 @@ The following algorithms are provided:
280284 Many thanks to Sebastiano Vigna for his help with the 58 bit adaption.
281285
282286- **`exrop`** *(Since OTP 20.0)*
283- Xoroshiro116+, 58 bits precision and period of 2^116-1
287+ Xoroshiro116+, 58 bits precision and period of 2^116-1.
284288
285- Jump function: equivalent to 2^64 calls
289+ Jump function: equivalent to 2^64 calls.
286290
287291- **`exs1024s`** *(Since OTP 20.0)*
288292 Xorshift1024\*, 64 bits precision and a period of 2^1024-1
289293
290- Jump function: equivalent to 2^512 calls
294+ Jump function: equivalent to 2^512 calls.
295+
296+ Since this generator operates on 64-bit integers that are bignums
297+ on 64 bit platforms, it is much slower than `exro928ss` above.
291298
292299- **`exsp`** *(Since OTP 20.0)*
293300 Xorshift116+, 58 bits precision and period of 2^116-1
294301
295- Jump function: equivalent to 2^64 calls
302+ Jump function: equivalent to 2^64 calls.
296303
297304 This is a corrected version of a previous
298305 [_default algorithm_](#default-algorithm) (`exsplus`, _deprecated_),
299306 that was superseded by Xoroshiro116+ (`exrop`). Since this algorithm
300- does not use rotate it executes a little (say < 15%) faster than `exrop`
301- (that has to do a 58 bit rotate, for which there is no native instruction).
307+ does not use rotate operations it executes a little (say < 15%) faster
308+ than `exrop` (that has to do a 58 bit rotate,
309+ for which there is no native instruction).
302310 See the [algorithms' homepage](http://xorshift.di.unimi.it).
303311
304312[](){: #default-algorithm }
@@ -310,7 +318,9 @@ required, ensure to always use `seed/1` to initialize the state.
310318
311319Which algorithm that is the default may change between Erlang/OTP releases,
312320and is selected to be one with high speed, small state and "good enough"
313- statistical properties.
321+ statistical properties. So to ensure that the same sequence is reproduced
322+ on a later Erlang/OTP release, use a `seed/2` or `seed_s/2` to select
323+ both a specific algorithm and the seed value.
314324
315325#### Old Algorithms
316326
@@ -1050,7 +1060,7 @@ The concept implicates that the probability to get exactly zero is extremely
10501060low; so low that this function in fact never returns `0.0`.
10511061The smallest number that it *might* return is `DBL_MIN`,
10521062which is `2.0^(-1022)`. However, the generators in this module
1053- has thechnical limitations on how many zero words in a row they
1063+ have technical limitations on how many zero words in a row they
10541064*can* return, which limits the number of leading zeros
10551065that *can* be generated, which sets an upper limit for the smallest
10561066generated number, that is still extremely small.
@@ -1062,7 +1072,7 @@ never returns exactly `0.0` is impossible to observe.
10621072
10631073For all sub ranges `N*2.0^(-53) =< X < (N+1)*2.0^(-53)` where
10641074`0 =< integer(N) < 2.0^53`, the probability to generate a number
1065- in a sub range range is the same, very much like the numbers generated by
1075+ in a sub range is the same, very much like the numbers generated by
10661076`uniform_s/1`.
10671077
10681078Having to generate extra random bits for occasional small numbers
@@ -1251,7 +1261,7 @@ as required to compose the `t:binary/0`. Returns the generated
12511261>
12521262> The `m:crypto` module contains a function `crypto:strong_rand_bytes/1`
12531263> that does the same thing, but cryptographically secure.
1254- > It is pretty fast and effective on modern systems.
1264+ > It is pretty fast and efficient on modern systems.
12551265>
12561266> This function, however, offers the possibility to reproduce
12571267> a byte sequence by re-using seed, which a cryptographically secure
@@ -1261,10 +1271,10 @@ as required to compose the `t:binary/0`. Returns the generated
12611271> random integers, thus has to create bytes from integers,
12621272> it becomes rather slow.
12631273>
1264- > Particularly ineffective and slow is to use
1274+ > Particularly inefficient and slow is to use
12651275> a [`rand` plug-in generator](#plug-in-framework) from `m:crypto`
12661276> such as `crypto:rand_seed_s/0` to call this function for generating
1267- > bytes. Since it in that case is not possible to reproduce
1277+ > bytes. Since in that case it is not possible to reproduce
12681278> the byte sequence anyway; it is better to use
12691279> `crypto:strong_rand_bytes/1` directly.
12701280""" .
@@ -2462,9 +2472,14 @@ adding up to 59 bits, which is not a bignum (on a 64-bit VM ):
24622472""" .
24632473-doc (#{group => <<" Niche algorithms API" >>,since => <<" OTP 25.0" >>}).
24642474-spec mwc59_value (CX :: mwc59_state ()) -> V :: 0 ..? MASK (59 ).
2465- mwc59_value (CX ) when is_integer (CX ), 1 =< CX , CX < ? MWC59_P ->
2466- CX2 = CX bxor ? BSL (59 , CX , ? MWC59_XS1 ),
2467- CX2 bxor ? BSL (59 , CX2 , ? MWC59_XS2 ).
2475+ -define (
2476+ mwc59_value (CX0 , CX1 ),
2477+ begin
2478+ CX1 = (CX0 ) bxor ? BSL (59 , (CX0 ), ? MWC59_XS1 ),
2479+ CX1 bxor ? BSL (59 , CX1 , ? MWC59_XS2 )
2480+ end ).
2481+ mwc59_value (CX0 ) when is_integer (CX0 ), 1 =< CX0 , CX0 < ? MWC59_P ->
2482+ ? mwc59_value (CX0 , CX1 ).
24682483
24692484-doc """
24702485Calculate a scrambled `t:float/0` from a [MWC59 state](`t:mwc59_state/0`).
@@ -2477,11 +2492,8 @@ The generator state is scrambled as with
24772492""" .
24782493-doc (#{group => <<" Niche algorithms API" >>,since => <<" OTP 25.0" >>}).
24792494-spec mwc59_float (CX :: mwc59_state ()) -> V :: float ().
2480- mwc59_float (CX1 ) when is_integer (CX1 ), 1 =< CX1 , CX1 < ? MWC59_P ->
2481- CX = ? MASK (53 , CX1 ),
2482- CX2 = CX bxor ? BSL (53 , CX , ? MWC59_XS1 ),
2483- CX3 = CX2 bxor ? BSL (53 , CX2 , ? MWC59_XS2 ),
2484- CX3 * ? TWO_POW_MINUS53 .
2495+ mwc59_float (CX0 ) when is_integer (CX0 ), 1 =< CX0 , CX0 < ? MWC59_P ->
2496+ ? MASK (53 , ? mwc59_value (CX0 , CX1 )) * ? TWO_POW_MINUS53 .
24852497
24862498-doc """
24872499Create a [MWC59 generator state](`t:mwc59_state/0`).
0 commit comments