


MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



NAME
     init_rng, kill_rng, dxrandomrv, dxrandomr, dxrandomv, dxran-
     dom, fxrandomrv, fxrandomr, fxrandomv, fxrandom, lxrandomrv,
     lxrandomr,  lxrandomv,  lxrandom,   bxrandomrv,   bxrandomr,
     bxrandomv, bxrandom, bxrandomrv_f, bxrandomr_f, bxrandomv_f,
     bxrandom_f, drandomrv, drandomr,  drandomv,  drandom,  fran-
     domrv,  frandomr,  frandomv,  frandom,  lrandomrv, lrandomr,
     lrandomv, lrandom, brandomrv, brandomr,  brandomv,  brandom,
     brandomrv_f,  brandomr_f,  brandomv_f, brandom_f, mrandomrv,
     mrandomr,   mrandomv,    mrandom,    flush_rng,    save_rng,
     restart_rng,  seed_rng,  check_rng, describe_rng, mralg_rng,
     split_rng, range_rng - a uniform interface to several random
     number generators

SYNOPSIS
     RNGdata *init_rng(alg, mrandom_alg, seed, count1, count2,
     long alg, mrandom_alg, *seed, count1, count2,

     int kill_rng(rng)
     RNGdata *rng;

     double dxrandomrv(rng, n, v)
     RNGdata *rng;
     long n;
     double v[];

     float fxrandomrv(rng, n, v)
     RNGdata *rng;
     long n;
     float v[];

     long lxrandomrv(rng, n, v)
     RNGdata *rng;
     long n;
     long v[];

     long lxrandomv(n, v)
     long n;
     long v[];

     int bxrandomrv(rng, n, v)
     RNGdata *rng;
     long n;
     int v[];

     int bxrandomrv_f(rng, n, v)
     RNGdata *rng;
     long n;
     int v[];

     double drandomrv(rng, n, v)
     RNGdata *rng;



Sun Release 4.1       Last change: 5/28/93                      1






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     long n;
     double v[];

     float frandomrv(rng, n, v)
     RNGdata *rng;
     long n;
     float v[];

     long lrandomrv(rng, n, v)
     RNGdata *rng;
     long n;
     long v[];

     int brandomrv(rng, n, v)
     RNGdata *rng;
     long n;
     int v[];

     int brandomrv_f(rng, n, v)
     RNGdata *rng;
     long n;
     int v[];

     long mrandomrv(rng, m, n, v)
     RNGdata *rng;
     long m;
     long n;
     long v[];

     int save_rng(rng, filename)
     RNGdata *rng;
     char *filename;

     RNGdata *restart_rng(rng, filename)
     char *filename;

     void seed_rng(rng, seed)
     RNGdata *rng;
     long *seed;

     int check_rng(rng);
     RNGdata *rng;

     char *describe_rng(rng, rngid)
     RNGdata *rng;
     char rngid[RNGIDSTRLEN];

     int mralg_rng(rng,new_value)
     RNGdata *rng;
     long new_value;





Sun Release 4.1       Last change: 5/28/93                      2






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     int split_rng(rng, new_value)
     RNGdata *rng;
     long new_value;

     double range_rng(rng)
     RNGdata *rng;

DESCRIPTION
     _m_r_a_n_d_o_m_r_v(_r_n_g,_m,_n,_v) generates  n  random  integers  in  the
     range 0 to m-1, using the generator rng, and storing them in
     vector v.  An initialization routine, _i_n_i_t__r_n_g(),  described
     below, allows you to select an appropriate generator.

     Using this package, instead of direct calls to  random()  or
     some other RNG code, offers the following advantages.

     1.   You can switch to another RNG, and re-run a portion  of
          your experiment to check its validity, without changing
          any of your code other than a single parameter in  your
          _i_n_i_t__r_n_g() call.

     2.   You can use my unbiased method  for  generating  random
          integers in the range 0..m-1.  By contrast, the typical
          integer-generating codes "random()%m"  or  "(int)  m  *
          ((double)  random()/MAXLONG)"  have  a  slight bias for
          large m.

     3.   Floating point numbers, uniformly distributed in  [0.0,
          1.0), are available (as on most RNG interfaces).

     4.   As  with  most  RNG  interfaces,  you  can  have   many
          simultaneously-active   RNGs.   (Unfortunately,  I  was
          unable to find  an  efficient  work-around  for  4.3bsd
          random()'s  state-saving bug; you'll have to use one of
          the other generators if you want to  use  multiple  RNG
          streams in a single program invocation.)

     5.   Time-efficient  vectorized  calls,  returning  multiple
          uniform variates, are available.

     6    The ability to "split" RNGs to produce parallet  output
          streams using the "leapfrog" method.

     7.   The package offers a shorthand notation for  completely
          specifying  the  algorithm  and  current  state of your
          RNG(s), in an 80-character human-readable ASCII string.
          This  is  very useful in experimental documentation and
          replication.

     8.   A complete RNG state can  be  (serially)  reconstructed
          from its shorthand notation, and




Sun Release 4.1       Last change: 5/28/93                      3






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     9.   A file-I/O interface allows fast saves and restarts  of
          complete  RNG  state vectors, without the time overhead
          of serial reconstruction.


     Also included in this software release  is  a  (unsupported)
     driver routine _m_r_t_e_s_t._c. This routine implements some of the
     simpler tests of randomness, e.g. equidistribution, pairwise
     (both short- and long-range) correlation, and 3-tuple corre-
     lation [Marsaglia, 1985].  These tests were chosen to illus-
     trate the use of the components of the _m_r_a_n_d_o_m() package, as
     well as to exhibit the known defects of the  4.3bsd  genera-
     tors  rand()  and nrand48().  See the man page on _m_r_t_e_s_t for
     more details.

     Another use for _m_r_t_e_s_t._c is as a template for your own calls
     to  the  mrandom() package.  (I, for one, like to program by
     example...)

     Below are detailed descriptions of  the  interfaces  to  the
     various  C-language functions in the mrandom() package.  For
     technical  details,  consult  the  file  _m_r_a_n_d_o_m._t_e_x,   also
     included in this distribution.

     In order to use an RNG, it must first be initialized.   This
     is  accomplished  by first declaring a pointer to an RNGdata
     structure, and then calling  _i_n_i_t__r_n_g()  ,  which  allocates
     memory  for the RNG and readies it for use by the other rou-
     tines in the package.

     _i_n_i_t__r_n_g() returns a  pointer  to  an  initialized  RNG.   A
     pointer returned by _i_n_i_t__r_n_g() _i_s _v_a_l_i_d _f_o_r _u_s_e _b_y

     In an init_rng() call, the _a_l_g parameter should have a value
     between 0 and 9, to indicate which RNG algorithm is desired:

     1.   4.3bsd random(), a non-linear additive feedback RNG,

     2.   The Knuth/Bentley prand(), a lagged-Fibonnacci  genera-
          tor with a state table of size 55 [Bentley, 1992],

     3.   4.3bsd nrand48(), a 48-bit multiplicative  congruential
          RNG,

     4.   L'Ecuyer's ``portable combined'' 32-bit  multiplicative
          congruential generator [L'Ecuyer, 1988],

     5.   4.3bsd rand(), the  discredited  32-bit  multiplicative
          congruential RNG, and

     6-8. Press & Teukolsky's ran0, ran1, and ran2,  respectively
          [Press & Teukolsky, 1992],



Sun Release 4.1       Last change: 5/28/93                      4






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     9.   Marsaglia's subtract-with-borrow Ultra generator  [Mar-
          saglia and Zaman, 1991],

     0.   for testing  purposes,  a  linear  additive  generator,
          "long state=seed1; state += seed2", capable of generat-
          ing any 32-bit constant or any arithmetic sequence.

          _m_r_a_n_d_o_m__a_l_g is the algorithm to be used by  _m_r_a_n_d_o_m_r_v()
          _w_h_e_n called with the RNG.


     The seed and count parameters are  used  for  initialization
     and  ``cycling'' of the generator before control is returned
     to the  calling  program.   The  generator  will  be  cycled
     count1+(1.0e9)*count2  times,  so  beware: if count2 is non-
     zero, the underlying RNG will be called  billions  of  times
     before  control  is  returned  to the calling program!  Most
     generators take just one 32-bit seed, but the  _s_e_e_d  parame-
     ters points to a vector of seeds, whose length is determined
     by the needs of the underlying generator.

     _i_n_i_t__r_n_g() returns a pointer to the allocated  and  initial-
     ized RNG.

     _b_u_f_s_i_z_e is the size  of  the  RNG's  main  buffer.   A  non-
     positive value of _b_u_f_s_i_z_e _w_i_l_l _b_e _i_n_t_e_r_p_r_e_t_e_d _a_s _a

     _k_i_l_l__r_n_g() destroys the RNG,  making  it  invalid  for  use.
     This  procedure  de-allocates the space used by the RNG, and
     should therefore be used to kill RNGs which will  no  longer
     be used.

     Do _n_o_t use an _R_N_G_d_a_t_a

     pointer which points to an active RNG to  store  the  return
     value  of .I init_rng().  In order to initialize an RNG, you
     should either declare a new _R_N_G_d_a_t_a pointer, and then use it
     to  store the return value of _i_n_i_t__r_n_g(), or, use _k_i_l_l__r_n_g()
     to de-initialize an  _R_N_G_d_a_t_a  pointer  which  points  to  an
     active  RNG,  and  then use that pointer to store the return
     value of _i_n_i_t__r_n_g()

     In general, I believe that users should extend the  sequence
     of  an existing RNG, whenever possible, instead of seeding a
     new one.  I suggest this methodology because it is so diffi-
     cult  to  properly seed an RNG when performing multiple pro-
     gram runs during a single experiment.  Where, after all, can
     you  get  truly  random seeds?  To use the time of day, or a
     process ID, is to invite disaster  in  the  form  of  subtle
     experimental   correlations  or  the  (often  not-so-subtle)
     effects of inadvertent reuse of a seed.  Note  that  if  you
     use  a  ``perfectly random'' RNG to generate seeds uniformly



Sun Release 4.1       Last change: 5/28/93                      5






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     distributed in 0..2^{31}-1, you  will  are  very  likely  to
     reuse  a  seed  -- and thus risk a duplicated program run --
     after running, say, thirty thousand experiments.

     Accordingly, my package makes it easy to  save  and  restart
     RNGs,   to   minimize   the  attraction  of  reseeding  with
     init_rng() calls.  The  call  _s_a_v_e__r_n_g(_r_n_g,  _f_i_l_e_n_a_m_e)  will
     write  a  complete  state  table to the specified file.  The
     files are in human-readable ASCII, and are never  more  than
     about 1000 characters.  The return value of save_rng is 1 if
     the file is successfully created; 0 otherwise.

     The call _r_e_s_t_a_r_t__r_n_g(_f_i_l_e_n_a_m_e) reads the specified file into
     and  returns a pointer to the RNG constructed from the file.
     A null pointer is returned, and  a  message  is  printed  to
     stderr,  if the restart fails due to a garbled or unreadable
     statefile.  Otherwise restart_rng returns the value 1.

     A major advantage of using restart_rng instead  of  init_rng
     is  that the time required to initialize the RNG is indepen-
     dent of the value of the count1, count2 parameters.


     Several routines are available for  generating  pseudorandom
     numbers.   Both  buffered  and  unbuffered routines are pro-
     vided.  Unbuffered routines call the underlying RNG only  as
     many  times as are needed to produce the requested number of
     generates, while buffered routines maintain buffers of  gen-
     erates,  so  that generates may be produced efficiently even
     when requested in small quantities.  Roughly, buffered  rou-
     tines  are  preferable when generates are requested one at a
     time or in small quantities, while unbuffered  routines  are
     preferable when generates are requested in large quantities.
     For detailed information about buffering, seed  mrandom.tex,
     included in this distribution.

     The name of a routine denotes the type of  the  value  which
     the  routine  returns and whether the routine is buffered or
     unbuffered. The first letter of a routine denotes  the  type
     of  value  which  it returns: ``d'' for double precision and
     ``f'' for single  precision  floating  point  in  the  range
     [0,1);    ``l''    for    long    integer   in   the   range
     0..(range_rng(rng)-1), and ``b'' for bit (either a  0  or  a
     1).  If the second letter of the routine's name is an ``x'',
     then the routine is unbuffered.  Otherwise, the  routine  is
     buffered.

     For convenience in  user  programming,  we  also  provide  a
     number  of macros that supply default parameter values.  The
     last two letters of all our fundamental routines is  ``rv''.
     This means that they must be provided with both a pointer to
     an RNGdata structure and a vector  to  fill  with  generates



Sun Release 4.1       Last change: 5/28/93                      6






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     from  the  RNG.   Macros whose names do not contain an ``r''
     have the RNGdata pointer omitted from their parameter  list;
     they  use  the most-recently initialized or restarted RNG to
     produce generates.  Macros whose  names  do  not  contain  a
     ``v''  have  the vector and number of generates omitted from
     their parameter list; they produce and return a single  gen-
     erate.

     All generating routines abort with a message  to  stderr  if
     called with an invalid RNGdata pointer.

     The two routines for  generating  bits  deserve  some  extra
     attention.   _b_x_r_a_n_d_o_m_r_v()  and _b_r_a_n_d_o_m_r_v() each use one gen-
     erate from the RNG to generate each bit.  _b_x_r_a_n_d_o_m_r_v__f() and
     _b_r_a_n_d_o_m_r_v__f()  use  each generate to produce 32 bits.  These
     two routines can only be used with 32-bit  generators;  they
     return -1 otherwise.

     _m_r_a_n_d_o_m_r_v() fills the vector v with n generates in the range
     0..m-1.   If  range_rng(rng) < m, the program aborts with an
     error.

     The algorithm used by  _m_r_a_n_d_o_m_r_v()  to  fill  v  is  set  by
     _i_n_i_t__r_n_g or by _m_r_a_l_g__r_n_g.

     Algorithm 0 is Thomborson's unbiased method, which  produces
     unbiased  long  integers in the range [0..m).  The algorithm
     discards any outputs from rng which are larger than r-(r mod
     m), where r is equal to range_rng(rng).  At worst, this code
     will discard (on long-term average) at most one value  of  r
     for  every  one  that  is  useful.   This worst case is only
     encountered for extremely large m; for fixed and moderate m,
     this  code  will  rarely  discard a value, and thus will run
     essentially as fast as algorithm 1.  When  the  value  of  m
     changes  on each call to _m_r_a_n_d_o_m_r_v() , however, this code is
     slower than algorithm 1, due to the necessity of recomputing
     r-(r mod m).

     The program aborts with an error message to stderr if rng is
     behaving  so  non-randomly  that  Algorithm  0  must make an
     excessive number of calls to rng in  order  to  produce  the
     requested number of generates.

     Algorithm 1 is the standard (long)(m*dxrandomr(rng)).   This
     algorithm may be biased: for large m, some results may be be
     more likely than others.  The bias is (r mod m)/m, which  is
     upper-bounded  by  0.1%  if m is less than a million and the
     range r of rng is at least a billion.

     We do not support, and indeed we actively  discourage,  gen-
     erating   restricted-range  integers  with  lrandomr(rng)%m.
     Many RNGs have poor behavior under this transformation, most



Sun Release 4.1       Last change: 5/28/93                      7






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     noticeably when m is a power of 2.  When m is not a power of
     2, fixed-point division required by an  ``%''  operation  is
     time-consuming on many workstations.


NOTES
     The  mrandomrv  procedure  is  capable  of  generating  long
     integers  in  the  full  range  of  any  RNG  for which 1 <=
     range_rng(rng) <= 2^32.  In order to accomplish  this,  with
     the parameter m a signed long integer, the following mapping
     is used:

     Range(mrandom(m))  =  0..m-1         if  1  <=  m   <   2^31
                      0..    2^32-1         if   m=0
     0..(2^31-m-1)   if -2^31 <= m < 0


     _s_e_e_d__r_n_g() seeds rng with the seed table pointed to by seed.
     The RNG's counter is reset to 0.


     _c_h_e_c_k__r_n_g() checks the integrity of the  RNG,  in  order  to
     determine  whether  it  can  be  used  by  the other mrandom
     library routines.


     _d_e_s_c_r_i_b_e__r_n_g() places a human-readable description of rng in
     the string rngid.


     _m_r_a_l_g__r_n_g() sets the mrandom algorithm number of rng.


     _s_p_l_i_t__r_n_g() sets the split value of rng.


     returns the range of rng.


AUTHOR
     Robert Plotkin, rplotkin@athena.mit.edu and  Clark  Thombor-
     son, cthombor@ub.d.umn.edu

DIAGNOSTICS
     If error-checking code in any of the  routines  discovers  a
     problem, an error message is printed on the stderr stream.


SEE ALSO
     random(3), rand(3C), drand48(3), mrtest(1)





Sun Release 4.1       Last change: 5/28/93                      8






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



BUGS
     A little slower than _r_a_n_d_o_m().

     A source-code rewrite of  random()  would  allow  efficient,
     bug-free, state-saving and restarting.  As things stand, you
     can get "non-random" and "non-restartable"  RNG  streams  by
     calling  init_rng()  several  times  with  alg=1.  Perhaps I
     should add code to generate an error message in this case.


THEORY
     Aside from the bug with multiple simultaneous generators,  I
     know  of  no  reason  to  choose  4.3bsd  random()  over the
     Knuth/Bentley RNG.  Both  are  likely  to  fail  Marsaglia's
     Birthday-Spacings  test, although I don't know that this has
     been tested (and I don't see that this is likely to  pose  a
     problem in any ``real'' application).  The portable-combined
     RNG is noticeably slower, but arguably superior to both  the
     above.   The  defects  of  4.3bsd  rand()  and nrandom() are
     fairly well-known, and they are only included in this  pack-
     age for reasons of backward compatibility and testing.

     For more information on this package, see  the  LaTex  files
     mrandom.tex and soda.tex included with this distribution.


REFERENCES
     Jon Louis Bentley, ``The software exploratorium: Some random
     thoughts.'' _U_N_I_X _R_e_v_i_e_w _1_0, Number 6, June 1992.

     Pierre L'Ecuyer, ``Efficient and  portable  combined  random
     number  generators.'' _C_o_m_m_u_n_i_c_a_t_i_o_n_s _o_f _t_h_e _A_C_M, _3_1(_6): 742-
     -774, June 1988.

     George Marsaglia, ``A current view of random number  genera-
     tors.''  In L. Billard, editor, _C_o_m_p_u_t_e_r _S_c_i_e_n_c_e _a_n_d _S_t_a_t_i_s_-
     _t_i_c_s: _T_h_e _I_n_t_e_r_f_a_c_e, pages 3--10. Elsevier Science  Publish-
     ers, 1985.

     George Marsaglia and Arif Zaman, ``A  New  Class  of  Random
     Number  Generators.''  _T_h_e  _A_n_n_a_l_s  _o_f  _A_p_p_l_i_e_d _P_r_o_b_a_b_i_l_i_t_y,
     _1(_3): 1991.

     Ora E. Percus and Malvin H. Kalos, ``Random  number  genera-
     tors for MIMD parallel processors.'' _J_o_u_r_n_a_l _o_f _P_a_r_a_l_l_e_l _a_n_d
     _D_i_s_t_r_i_b_u_t_e_d _C_o_m_p_u_t_i_n_g, 477--497, 1989.

     William H. Press and Saul A.  Teukolsky,  ``Portable  Random
     Number  Generators.''  _C_o_m_p_u_t_e_r_s _i_n _P_h_y_s_i_c_s, _6(_5): Sept/Oct.
     1992.

     Robert Sedgewick, _A_l_g_o_r_i_t_h_m_s _i_n _C, Addison-Wesley, 1990.



Sun Release 4.1       Last change: 5/28/93                      9






MRANDOM(3)             C LIBRARY FUNCTIONS             MRANDOM(3)



     Clark Thomborson, "Tools for Randomized Experimentation," to
     appear in the _P_r_o_c_e_e_d_i_n_g_s _o_f _t_h_e _2_5_t_h _S_y_m_p_o_s_i_u_m _o_n _C_o_m_p_u_t_i_n_g
     _S_c_i_e_n_c_e _a_n_d _S_t_a_t_i_s_t_i_c_s, 1993.

     Clark     Thomborson.      ``Mrandom     (version      1).''
     _C_o_m_p._s_o_u_r_c_e_s._u_n_i_x _2_5(_2_3), December 1991.

















































Sun Release 4.1       Last change: 5/28/93                     10



