RandomLongStream

© 2010 John Abbott
GNU Free Documentation License, Version 1.2



CoCoALib Documentation Index

User documentation for RandomLongSteam

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 RandomBoolStream for information about generating random bools, and RandomZZStream for information about generating random large integers. An alternative way of generating random values is to use a RandomSource.

Examples

Constructors

There are three ways of creating a new RandomLongSteam object:

    RandomLongStream RLS1(lo,hi);      // seeded with 1 by default
    RandomLongStream RLS2(lo,hi, n);   // seed generator with abs(n)

Each generator will produce values uniformly distributed in the range from lo to hi (with both extremes included). An ERR::BadArg exception is thrown if lo > hi; the case lo == hi is allowed.

The third argument is for seeding the generator. If you create more than one RandomLongStream object with the same seed (and range), they will each produce exactly the same sequence of values. In particular, to obtain different results each time a program is run, you can for instance seed the generator with the system time (e.g. by supplying as argument time(0)); this is likely desirable unless you're trying to debug a randomized algorithm.

Operations

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.

Maintainer documentation for RandomLongSteam

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.

The data members myLwb, myUpb and myRange are morally constant, but I cannot make them const because I wanted to allow assignment of RandomLongStream objects.

Bugs, Shortcomings and other ideas

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.

Discarded idea: have a ctor for RLS which take a ref to a RandomSource, and which uses that to obtain randomness. I discarded the idea because of the risks of an "invisible external reference" (e.g. a dangling reference, or problems in multithreaded code). Instead of passing a reference to a RandomSource to the ctor, you can use the RandomSource to create an initial seed which is handed to the ctor -- this gives better separation.