mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
234 lines
8.7 KiB
Plaintext
234 lines
8.7 KiB
Plaintext
NAME
|
|
rand - additive 55 shuffle pseudo-random number generator
|
|
|
|
SYNOPSIS
|
|
rand([[min, ] max])
|
|
|
|
TYPES
|
|
min integer
|
|
max integer
|
|
|
|
return integer
|
|
|
|
DESCRIPTION
|
|
Generate a pseudo-random number using an additive 55 shuffle generator.
|
|
We return a pseudo-random number over the half closed interval [min,max).
|
|
By default, min is 0 and max is 2^64.
|
|
|
|
The shuffle method is fast and serves as a fairly good standard
|
|
pseudo-random generator. If you need a fast generator and do not
|
|
need a cryptographically strong one, this generator is likely to do
|
|
the job. Casual direct use of the shuffle generator may be
|
|
acceptable. For a much higher quality cryptographically strong
|
|
(but slower) generator use the Blum-Blum-Shub generator (see the
|
|
random help page).
|
|
|
|
Other arg forms:
|
|
|
|
rand() Same as rand(0, 2^64)
|
|
rand(max) Same as rand(0, max)
|
|
|
|
The rand generator generates the highest order bit first. Thus:
|
|
|
|
rand(256)
|
|
|
|
will produce the save value as:
|
|
|
|
(rand(8) << 5) + rand(32)
|
|
|
|
when seeded with the same seed.
|
|
|
|
The rand generator has two distinct parts, the additive 55 method
|
|
and the shuffle method. The additive 55 method is described in:
|
|
|
|
"The Art of Computer Programming - Seminumerical Algorithms"
|
|
by Knuth, Vol 2, 2nd edition (1981), Section 3.2.2, page 27,
|
|
Algorithm A.
|
|
|
|
The period and other properties of the additive 55 method
|
|
make it very useful to 'seed' other generators.
|
|
|
|
The shuffle method is feed values by the additive 55 method.
|
|
The shuffle method is described in:
|
|
|
|
"The Art of Computer Programming - Seminumerical Algorithms"
|
|
by Knuth, Vol 2, 2nd edition (1981), Section 3.2.2, page 32,
|
|
Algorithm B.
|
|
|
|
The rand generator has a good period, and is fast. It is reasonable as
|
|
generators go, though there are better ones available. The shuffle
|
|
method has a very good period, and is fast. It is fairly good as
|
|
generators go, particularly when it is feed reasonably random
|
|
numbers. Because of this, we use feed values from the additive 55
|
|
method into the shuffle method.
|
|
|
|
The rand generator uses two internal tables:
|
|
|
|
additive table - 55 entries of 64 bits used by the additive 55 method
|
|
|
|
shuffle table - 256 entries of 64 bits used by the shuffle method
|
|
feed by the additive 55 method from the additive table
|
|
|
|
The goals of this generator are:
|
|
|
|
* all magic numbers are explained
|
|
|
|
I (Landon Curt Noll) distrust systems with constants (magic
|
|
numbers) and tables that have no justification (e.g.,
|
|
DES). I believe that I have done my best to justify all of
|
|
the magic numbers used.
|
|
|
|
* full documentation
|
|
|
|
You have this source file, plus background publications,
|
|
what more could you ask?
|
|
|
|
* large selection of seeds
|
|
|
|
Seeds are not limited to a small number of bits. A seed
|
|
may be of any size.
|
|
|
|
Most of the magic constants used by this generator ultimately are
|
|
based on the Rand book of random numbers. The Rand book contains
|
|
10^6 decimal digits, generated by a physical process. This book,
|
|
produced by the Rand corporation in the 1950's is considered
|
|
a standard against which other generators may be measured.
|
|
|
|
The Rand book of numbers was groups into groups of 20 digits. The
|
|
first 55 groups < 2^64 were used to initialize the default additive
|
|
table. The size of 20 digits was used because 2^64 is 20 digits
|
|
long. The restriction of < 2^64 was used to prevent modulus biasing.
|
|
|
|
The shuffle table size is longer than the 100 entries recommended
|
|
by Knuth. We use a power of 2 shuffle table length so that the
|
|
shuffle process can select a table entry from a new additive 55
|
|
value by extracting its low order bits. The value 256 is convenient
|
|
in that it is the size of a byte which allows for easy extraction.
|
|
|
|
We use the upper byte of the additive 55 value to select the
|
|
shuffle table entry because it allows all of 64 bits to play a part
|
|
in the entry selection. If we were to select a lower 8 bits in the
|
|
64 bit value, carries that propagate above our 8 bits would not
|
|
impact the additive 55 generator output.
|
|
|
|
It is 'nice' when a seed of "n" produces a 'significantly different'
|
|
sequence than a seed of "n+1". Generators, by convention, assign
|
|
special significance to the seed of '0'. It is an unfortunate that
|
|
people often pick small seed values, particularly when large seed
|
|
are of significance to the generators found in this file. An internal
|
|
process called randreseed64 will effectively eliminate the human
|
|
perceptions that are noted above.
|
|
|
|
It should be noted that the purpose of randreseed64 is to scramble a
|
|
seed ONLY. We do not care if these generators produce good random
|
|
numbers. We only want to help eliminate the human factors & perceptions
|
|
noted above.
|
|
|
|
The randreseed64 process scrambles all 64 bit chunks of a seed, by
|
|
mapping [0,2^64) into [0,2^64). This map is one-to-one and onto.
|
|
Mapping is performed using a linear congruence generator of the form:
|
|
|
|
X1 <-- (a*X0 + c) % m
|
|
|
|
with the exception that:
|
|
|
|
0 ==> 0 (so that srand(0) acts as default)
|
|
|
|
while maintaining a 1-to-1 and onto map.
|
|
|
|
The randreseed64 constants 'a' and 'c' based on the linear
|
|
congruential generators found in:
|
|
|
|
"The Art of Computer Programming - Seminumerical Algorithms"
|
|
by Knuth, Vol 2, 2nd edition (1981), Section 3.6, pages 170-171.
|
|
|
|
We will select the randreseed64 multiplier 'a' such that:
|
|
|
|
a mod 8 == 5 (based on note iii)
|
|
0.01*m < a < 0.99*m (based on note iv)
|
|
0.01*2^64 < a < 0.99*2^64
|
|
a is prime (help keep the generators independent)
|
|
|
|
The choice of the randreseed64 adder 'c' is considered immaterial
|
|
according (based in note v). Knuth suggests 'c==1' or 'c==a'. We
|
|
elect to select 'c' using the same process as we used to select
|
|
'a'. The choice is 'immaterial' after all, and as long as:
|
|
|
|
gcd(c, m) == 1 (based on note v)
|
|
gcd(c, 2^64) == 1
|
|
gcd(a, c) == 1 (adders & multipliers will be more independent)
|
|
|
|
The values 'a' and 'c for randreseed64 are taken from the Rand book
|
|
of numbers. Because m=2^64 is 20 decimal digits long, we will
|
|
search the Rand book of numbers 20 at a time. We will skip any of
|
|
the 55 values that were used to initialize the additive 55
|
|
generators. The values obtained from the Rand book are:
|
|
|
|
a = 6316878969928993981
|
|
c = 1363042948800878693
|
|
|
|
As we stated before, we must map 0 ==> 0 so that srand(0) does the
|
|
default thing. The randreseed64 would normally map as follows:
|
|
|
|
0 ==> 1363042948800878693 (0 ==> c)
|
|
|
|
To overcome this, and preserve the 1-to-1 and onto map, we force:
|
|
|
|
0 ==> 0
|
|
10239951819489363767 ==> 1363042948800878693
|
|
|
|
One might object to the complexity of the seed scramble/mapping via
|
|
the randreseed64 process. But Calling srand(0) with the randreseed64
|
|
process would be the same as calling srand(10239951819489363767)
|
|
without it. No extra security is gained or reduced by using the
|
|
randreseed64 process. The meaning of seeds are exchanged, but not
|
|
lost or favored (used by more than one input seed).
|
|
|
|
The randreseed64 process does not reduce the security of the rand
|
|
generator. Every seed is converted into a different unique seed.
|
|
No seed is ignored or favored.
|
|
|
|
The truly paranoid might suggest that my claims in the MAGIC NUMBERS
|
|
section are a lie intended to entrap people. Well they are not, but
|
|
you need not take my (Landon Curt Noll) word for it.
|
|
|
|
The random numbers from the Rand book of random numbers can be
|
|
verified by anyone who obtains the book. As these numbers were
|
|
created before I (Landon Curt Noll) was born (you can look up my
|
|
birth record if you want), I claim to have no possible influence on
|
|
their generation.
|
|
|
|
There is a very slight chance that the electronic copy of the
|
|
Rand book that I was given access to differs from the printed text.
|
|
I am willing to provide access to this electronic copy should
|
|
anyone wants to compare it to the printed text.
|
|
|
|
When using the a55 generator, one may select your own 55 additive
|
|
values by calling:
|
|
|
|
srand(mat55)
|
|
|
|
and avoid using my magic numbers. Of course, you must pick good
|
|
additive 55 values yourself!
|
|
|
|
EXAMPLE
|
|
> print srand(0), rand(), rand(), rand()
|
|
RAND state 14384206130809570460 10173010522823332484 5713611208311484212
|
|
|
|
> print rand(123), rand(123), rand(123), rand(123), rand(123), rand(123)
|
|
17 104 74 47 48 46
|
|
|
|
> print rand(2,12), rand(2^50,3^50), rand(0,2), rand(-400000, 120000)
|
|
11 170570393286648531699560 1 -96605
|
|
|
|
LIMITS
|
|
min < max
|
|
|
|
LIBRARY
|
|
void zrand(long cnt, ZVALUE *res)
|
|
void zrandrange(ZVALUE low, ZVALUE high, ZVALUE *res)
|
|
long irand(long max)
|
|
|
|
SEE ALSO
|
|
srand, randbit, isrand, random, srandom, israndom
|