The class RandomLongSteam
is for representing generators of (independent)
uniformly distributed random machine integers in a given range; the range is
specified when creating the generator (and cannot later be changed). See also
RandomBitStream
for information about generating random bits.
There are three ways of creating a new RandomLongSteam
object:
RandomLongStream RLS1(lo,hi); // default ctor, seeded with 1 RandomLongStream RLS2(lo,hi, n); // seed generator with abs(n) RandomLongStream RLS3(lo,hi, 0); // seed generator from current time
Each generator will produce values uniformly ditributed in the range from lo
to hi
(with both extremes included). An ERR::BadArg
exception is thrown
if lo >= hi
.
The third argument is for seeding the generator. Seeding from current time
will produce different results each time the program is run; this is likely
desirable unless you're trying to debug a randomized algorithm. Conversely,
if you create more than one RandomBitStream
object with the same parameters
(including the seed), they will each produce exactly the same sequence of numbers.
Once you have created a RandomLongStream
you may perform the following
operations on it:
*RLS // get the current value of RLS (as a signed long). ++RLS // advance to next value of RLS. RLS++ // advance to next value of RLS **INEFFICIENTLY**. sample(RLS) // advance RLS and then return new value; same as ``*++RLS`` out << RLS // print some information about RLS. RLS.myIndex() // number of times RLS has been advanced, same as the number of random values generated.
Note that a RandomLongStream
supports input iterator syntax.
You may assign or create copies of RandomLongStream
objects; the copies
acquire the complete state of the original, so will go on to produce exactly
the same sequence of bits as the original will produce.
The idea is very simple: use the pseudo random number generator of GMP to
generate a random machine integer in the range 0 to myRange-1
(where
myRange
was set in the ctor to be 1+myUpb-myLwb
) and then add that
to myLwb
. The result is stored in the data member myValue
so that
input iterator syntax can be supported.
There are two "non essential" data members: mySeed
and myCounter
.
I put these in to help any poor blighter who has to debug a randomized
algorithm, and who may want to "fast forward" the RandomLongSteam
to
the right place.
The data member myState
holds all the state information used by the GMP
generator. Its presence makes the ctors, dtor and assignment messier than
they would have been otherwise.
The advancing and reading member functions (i.e. operator++
and operator*
)
are inline for efficiency, as is the sample
function.
myGetValue
is a little messy because the value generated by the GMP function
gmp_urandomm_ui
cannot generate the full range of unsigned long
values.
So I have to call gmp_urandomb_ui
if the full range is needed.
Should the syntax for seeding from current time be more visibly different from the other ctor calls?
It might be neater to put ++myCounter
inside myGenValue
, though
this would mean that myCounter
gets incremented inside the ctor.
Should sample
advance before or after getting the value?
Is the information printed by myOutputSelf
adequate? Time will tell.