home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / lang / fortran / 4820 < prev    next >
Encoding:
Text File  |  1992-12-21  |  47.3 KB  |  1,038 lines

  1. Newsgroups: comp.lang.fortran
  2. Path: sparky!uunet!spool.mu.edu!umn.edu!msi.umn.edu!tregilli
  3. From: tregilli@s8.msi.umn.edu (Ian Lee Tregillis [Astro])
  4. Subject: Compilation of RNG responses
  5. Message-ID: <tregilli.724955552@msi.umn.edu>
  6. Sender: news@news2.cis.umn.edu (Usenet News Administration)
  7. Nntp-Posting-Host: s8.msi.umn.edu
  8. Organization: University of Minnesota
  9. Date: Mon, 21 Dec 1992 16:32:32 GMT
  10. Lines: 1026
  11.  
  12. Greetings, all-
  13.     Here it is, finally.  Though not as promptly as I should have,
  14. I've finally posted a summary of the responses I received regarding
  15. my request for a Fortran random-number generator.  I've left out
  16. the requests for me to share all of this stuff;  I will mail those people
  17. directly.  Also, I edited out extraneous material here and there to
  18. cut down on length;  deleted material is denoted with '[...]'.  Finally,
  19. messages are partitioned with a line of asterisks for ease in reading.
  20.     Again, thanks to everybody who responded!
  21.  
  22. Ian "Magnetic Moment" Tregillis
  23. tregilli@s1.msi.umn.edu
  24. treg0001@student.tc.umn.edu
  25.  
  26. >>Begin included text<<
  27. *************************************************************************
  28. Date: Mon, 16 Dec 1991 23:11:56 
  29. From: "Vladimir Vasilchenko" <vladimir@sur.rostov-na-donu.su>
  30. Organization: Mech & Appl Math Res Institute
  31.  
  32. Hi!
  33. Is it possible for You to test programs from the IMSL (Statistics) Library.
  34. This FORTRAN programs library I think is excellent tool for the specialists
  35. in statistics ( random number generators and so on .... ). Also I have some
  36. news about widely available statistics fortran library in Japan. My friend
  37. received so many programs from this library via Internet network. Moreover,
  38. You can try to find such programs in NAG library ( Oxford ), Cambridge fortran
  39. library ( Numerical Recipes ) and in the book "Computer methods of mathematical
  40. calculations" by Malcolm, Moler, Forsait ( Unfortunately, I don't remember
  41. the English form of the second names of these authors and here I retranslate
  42. ones from the Russian translation of this book. Sorry!).
  43. Best Regards,
  44. Vladimir V.Vasil'chenko, Russia, 16 December 1992.
  45. ***************************************************************************
  46. Date: Mon, 14 Dec 92 14:23:09 -0500
  47. From: "John D. McCalpin" <mccalpin@perelandra.cms.udel.edu>
  48. Organization: College of Marine Studies, U. Del.
  49.  
  50. [...]
  51. Try anonymous ftp to perelandra.cms.udel.edu.
  52. Look in pub/Math/random/.
  53. --
  54. John D. McCalpin                        mccalpin@perelandra.cms.udel.edu
  55. Assistant Professor                     mccalpin@brahms.udel.edu
  56. College of Marine Studies, U. Del.      John.McCalpin@mvs.udel.edu
  57. ***************************************************************************
  58. Date: Mon, 14 Dec 92 16:21:17 CST
  59. From: shepard@dirac.tcg.anl.gov (Ron Shepard)
  60.  
  61. Ian,  Look in "Computers in Physics, Vol. 6 No. 5 Sep/Oct 1992"
  62. on pp. 522-524.  At the top of page 523, there is a 12-line
  63. function ran0() that will probably work for your simple case.
  64.  
  65. Regards, -ron shepard
  66. ****************************************************************************
  67. Date: Mon, 14 Dec 92 17:28:53 PST
  68. Cc: dhall@wsuaix.csc.wsu.edu (david hall;WR5756)
  69.  
  70. THE source now is Numerical Recipes, second edition.  Skip the first edition;
  71. the random number section has been totally revised.  Or, the equivalent is in 
  72. Computers in Physics, 6(5), Seot-Oct 1992, Numerical Recipes section, "Portable 
  73. Random Number Generators," pp. 522-524.     I have lots of other references, 
  74. but these are handy, and in FORTRAN.  
  75.  
  76. Press, William H., Teukolsky, Saul A., Vetterling, William T., Flannery, Brian P.
  77. 1992.  Numerical Recipes in FORTRAN: the art of scientific computing. 2nd ed.
  78. Cambridge University Press.  QA297.N866
  79.  
  80. Would like to see what other references you are given...
  81.  
  82. David Hall - Programmer/Analyst (Masters thesis on RNG's).
  83. ***************************************************************************** 
  84. Date: Mon, 14 Dec 92 22:40:20 CST
  85. From: Jeff Haferman <haferman@icaen.uiowa.edu>
  86.  
  87. Actually, most "real" programmer don't always learn how to make
  88. "decent" random number generators.  To find really decent fortran
  89. source, find a copy of the newest edition of _Numerical_Recipes_in_
  90. Fortran_.  The old edition has some random number generators, but
  91. the latest edition has improved code.  Also, if you can find the 
  92. magazine "Computers in Physics", a month or two ago the authors
  93. of the aforementioned book wrote a wonderful column on random
  94. number generation, complete with Fortran source (very short).
  95. [...]
  96. Jeff Haferman
  97. *****************************************************************************
  98. Date: Mon, 14 Dec 92 23:29:51 CST
  99. From: Bradbury Franklin <franklin@math.wisc.edu>
  100.  
  101. Mr. Tregillis,
  102.  
  103.      The following subroutine takes the variance n and the global index J
  104.      as input and outputs m a normal random variable with mean 0 and variance
  105.      n.  Note that J is updated with each call of wiener, and the _main program
  106.      variable 'actual' parameter passed in the call of wienar should not be
  107.      touched by anything else in the program-- it is not a dummy variable. 
  108.      (Any initial integral value for J will do. This value is the random seed.)
  109.      Oh, and this will give 2**31-2 or so different numbers before cycling.
  110.  
  111.    Note that this is a rather poor random generator in that it exhibits 
  112.    clear lattice structure.   I have some better ones in C.  I will write it
  113.    in Fortran someday not too long from now...
  114.  
  115.    Also, see L'Ecuyer, P. "Efficient and Portable Combined Random Number 
  116.    Generators" Communications of the Assn. for Comptng Machin. 31 (1988) pp.742-
  117.    774. 
  118.     
  119.     SUBROUTINE wiener(m,n,J)
  120.        double precision m,n,a(2)
  121.        integer J,Q,R,S,U,V
  122.     R=7**5
  123.     C=2**31-1
  124.     do 120 S=1,2    
  125.     if (J.GT.2**31/R) then 
  126.       Q=J*R
  127.     else
  128.       V=MOD(J,127773)
  129.       U=(J-V)/127773
  130.       Q=-2836*V+R*U
  131.     end if
  132.     if (MOD(Q,C).LT.0) then
  133.      J=-MOD(Q,C)
  134.     else
  135.      J=MOD(Q,C)
  136.     end if
  137.     a(S)=float(J)/float(C)
  138. 120     continue
  139.        m=sqrt(-2*n*dlog(a(1)))*dsin(6.2832*a(2))
  140.        end
  141.  
  142. Brad Franklin
  143. franklin@math.wisc.edu
  144. ***************************************************************************
  145. Date: 15 Dec 92 14:35:33+0800
  146. From: Peter Hermann <ph@icavax.ica.uni-stuttgart.dbp.de>
  147.  
  148. Ian,
  149.  
  150. [...]
  151. Have a look at Communications of the acm -- Nov92.
  152.  
  153. Regards,
  154. Peter
  155. *****************************************************************************
  156. Date: Tue, 15 Dec 92 14:53:56 +0100
  157. From: rdd@spl6s2.aug.ipp-garching.mpg.de (Reinhard     Drube          E1 
  158.       )
  159.  
  160. Ian,
  161. I have one more hint for you to test the selected random number
  162. generator: Try to plot the produced numbers vs. the last number.
  163. On bad RND-generators you will see dependencies of the numbers
  164. in forms of circles, stripes and so on. A good generator will only
  165. produce random noise!  Again good luck!     Reinhard
  166. *****************************************************************************
  167. Date: Tue, 15 Dec 92 10:22:42 -0500
  168. From: Ji Wang <jiwang@phoenix.Princeton.EDU>
  169. Organization: Princeton University
  170.  
  171. Well, the easiest way is to check a library like NAG or IMSL, which 
  172. include a lot of subroutines for this purpose.  It is really easy
  173. to call.  And, check books on FORTRAN, you may find generator in many
  174. books.  Last, you definity have it n Numerical Recipes.
  175.  
  176. Ji Wang
  177. *****************************************************************************
  178. Date: Tue, 15 Dec 92 10:51:42 EST
  179. From: eiverson@Athena.MIT.EDU
  180.  
  181. I have enclosed a posting I saw a while ago about a library of
  182. random number generators from statlib.  Both statlib and netlib
  183. are vast repositories of code, and are really worth checking out.
  184.  
  185. netlib:
  186.     email netlib@ornl.gov or netlib@research.att.com
  187.         with body of message; 
  188.             send index
  189. or 
  190.     ftp  to research.att.com, login as netlib, and give e-mail
  191.     address as password.
  192.  
  193. statlib instructions given below.
  194.  
  195. Erik Iverson
  196. eiverson@athena.mit.edu
  197.  
  198. Begin included text...
  199.  
  200.                       Fortran version of RANLIB
  201.  
  202.  
  203. RANLIB is a collection of  Fortran routines that provide generators of
  204. random numbers from a variety of distributions.  RANLIB uses published
  205. algorithms, where available  (literature citations are included in the
  206. documentation).
  207.  
  208. RANLIB  is  available  via  anonymous   FTP from  odin.mda.uth.tmc.edu
  209. (129.106.3.17).  It is
  210.                         /pub/unix/ranlib.f.tar.Z
  211.  
  212. RANLIB   is  also   available   by   electronic   mail (or  ftp)  from
  213. statlib@lib.stat.cmu.edu.   The  file 'ranlib'  contains   an expanded
  214. description of the package; the file, 'ranlib.shar' contains  the full
  215. code and documentation.  To obtain both,  send mail with the following
  216. two lines to statlib@lib.stat.cmu.edu.
  217.          send ranlib from general
  218.          send ranlib.shar from general
  219. Those who are unfamiliar with statlib might want to add a third line
  220. to obtain an introductory document.
  221.          send index
  222.  
  223.                     Summary of Ranlib Capabilities
  224.  
  225. The bottom level routines provide 32 virtual random number generators.
  226. Each generator can provide 1,048,576 blocks of numbers, and each block
  227. is of length 1,073,741,824.  Any generator can be set to the beginning
  228. or end  of the current  block or to  its starting value.  Packaging is
  229. provided   so  that  if  these capabilities  are not  needed, a single
  230. generator with period 2.3 X 10^18 is seen.
  231.  
  232. Using this base, routines are provided that return:
  233.     (1)  Beta random deviates
  234.     (2)  Chi-square random deviates
  235.     (3)  Exponential random deviates
  236.     (4)  F random deviates
  237.     (5)  Gamma random deviates
  238.     (6)  Multivariate normal random deviates (mean and covariance
  239.          matrix specified)
  240.     (7)  Noncentral chi-square random deviates
  241.     (8)  Noncentral F random deviates
  242.     (9)  Univariate normal random deviates
  243.     (10) Random permutations of an integer array
  244.     (11) Real uniform random deviates between specified limits
  245.     (12) Binomial random deviates
  246.     (13) Poisson random deviates
  247.     (14) Integer uniform deviates between specified limits
  248.     (15) Seeds for the random number generator calculated from a
  249.          character string
  250. *****************************************************************************
  251. Date: Tue, 15 Dec 92 11:45:00 -0800
  252. From: dones@cloud9.arc.nasa.gov (Luke Dones)
  253.  
  254. Hi --
  255.  
  256.  I read two of your recent postings on random number generators and was
  257. wondering if you'd mind sharing the code/lore you'd collected. I recently had
  258. the unpleasant experience of reading an admission in Computers in Physics
  259. (Sep/Oct '92) by Press and Teukolsky that some of the random number generators
  260. in the first edition of Numerical Recipes, which I had used
  261. extensively, had problems (despite their previous lofty claims for how good
  262. they were!) Anyway, in CIP they give three new, supposedly improved codes, 
  263. which I enclose with this message (I have verified that they run, but have
  264. not tested them extensively). Even though they are now betting $1000 on the
  265. reliability of their new code, I still worry, so I would like to try some other
  266. routines.
  267.  
  268. Another possibly useful article appears in Dr. Dobb's Journal, Feb. 1992, pp.
  269. 34-40. This article gives code (in C) for random number generators with periods
  270. of ~4E9 and 1E27, if the author is to be believed....
  271.  
  272. Regards,
  273.  Luke Dones
  274. -----------------------------------------------------------------------------
  275.  
  276.       FUNCTION RAN0(IDUM)
  277. c    new routine: Computers in Physics 6, 522-524 (Sep/Oct 1992)
  278. c    "minimal standard" with period of 2**31 -2 ~ 2.1E9,
  279. c    but has serial correlations
  280. c    set idum = any integer except mask to initialize sequence
  281.       INTEGER IDUM,IA,IM,IQ,IR,MASK
  282.       REAL RAN0,AM
  283.       PARAMETER (IA=16807,IM=2147483647,AM=1./IM,
  284.      *    IQ=127773,IR=2836,MASK=123459876)
  285.       INTEGER K
  286.       IDUM=IEOR(IDUM,MASK)
  287.       K=IDUM/IQ
  288.       IDUM=IA*(IDUM-K*IQ)-IR*K
  289.       IF (IDUM.LT.0) IDUM=IDUM+IM
  290.       RAN0=AM*IDUM
  291.       IDUM=IEOR(IDUM,MASK)
  292.       RETURN
  293.       END
  294.     
  295.       FUNCTION RAN1(IDUM)
  296. c    new routine: minimal standard, shuffled
  297. c    claimed to be adequate for up to roughly 10**8 random deviates
  298. c     (5% of period)
  299. c    set idum = any negative integer to initialize sequence
  300. c    rnmx = "largest floating point value that is less than 1" --
  301. c     this looks dubious
  302.       INTEGER IDUM,IA,IM,IQ,IR,NTAB, ndiv
  303.       REAL RAN1,AM, eps, rnmx
  304.       PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,
  305.      *    NTAB=32,ndiv=1+(im-1)/ntab, eps = 1.2e-7, rnmx = 1. - eps)
  306.       INTEGER J,K, iv(ntab), iy
  307.       save iv, iy
  308.       data iv /NTAB*0/, iy /0/
  309.       if(idum.le.0 .or. iy.eq.0) then
  310.         IDUM=MAX(-IDUM,1)
  311.         DO J=NTAB+8,1,-1
  312.           K=IDUM/IQ
  313.           IDUM=IA*(IDUM-K*IQ)-IR*K
  314.           IF (IDUM.LT.0) IDUM=IDUM+IM
  315.           if(j.le.NTAB)iv(j)=idum
  316.     enddo
  317.         iy=iv(1)
  318.       ENDIF
  319.         K=IDUM/IQ
  320.         IDUM=IA*(IDUM-K*IQ)-IR*K
  321.         IF (IDUM.LT.0) IDUM=IDUM+IM
  322.         j = 1+iy/ndiv
  323.         iy=iv(j)
  324.         iv(j) = idum
  325.         ran1 = min(am*iy,rnmx)
  326.       RETURN
  327.       END
  328.     
  329.       FUNCTION RAN2(IDUM)
  330. c    Long-period (> 2E18) random number generator of L'Ecuyer
  331. c     with Bays-Durham shuffle
  332. c    set idum = any negative integer to initialize sequence
  333.       INTEGER IDUM,IM1,IM2,IMM1,IA1,IA2,IQ1,IQ2,IR1,IR2,NTAB, ndiv
  334.       REAL RAN2,AM,eps,rnmx
  335.       PARAMETER (IM1=2147483563,IM2=2147483399,AM=1./IM1,IMM1=IM1-1,
  336.      *    IA1=40014,IA2=40692,IQ1=53668,IQ2=52774,IR1=12211,
  337.      *    IR2=3791,NTAB=32,ndiv=1+imm1/ntab,eps=1.2e-7,
  338.      *    rnmx=1.-eps)
  339.       INTEGER IDUM2,J,K,IV(NTAB),iy
  340.       SAVE IV,IY,IDUM2
  341.       DATA IDUM2/123456789/, IV/NTAB*0/, IY/0/
  342.       IF (IDUM.LE.0) THEN
  343.         IDUM=MAX(-IDUM,1)
  344.         IDUM2=IDUM
  345.         DO J=NTAB+8,1,-1
  346.           K=IDUM/IQ1
  347.           IDUM=IA1*(IDUM-K*IQ1)-K*IR1
  348.           IF (IDUM.LT.0) IDUM=IDUM+IM1
  349.           if(j .le. ntab)IV(J)=IDUM
  350.     enddo
  351.         IY=IV(1)
  352.       ENDIF
  353.         K=IDUM/IQ1
  354.         IDUM=IA1*(IDUM-K*IQ1)-K*IR1
  355.         IF (IDUM.LT.0) IDUM=IDUM+IM1
  356.         K=IDUM2/IQ2
  357.         IDUM2=IA2*(IDUM2-K*IQ2)-K*IR2
  358.         IF (IDUM2.LT.0) IDUM2=IDUM2+IM2
  359.         J=1+IY/ndiv
  360.         iy=iv(j)-idum2
  361.         IV(J)=IDUM
  362.         IF(iy.LT.1)iy=iy+IMM1
  363.         RAN2=min(am*iy,rnmx)
  364.       RETURN
  365.       END
  366. [...]
  367. ****************************************************************************
  368. From: a@mga.com
  369. Date: Tue, 15 Dec 1992 22:36:44 -0500 (EST)
  370.  
  371. Here is a good random number generator.  Look at the reference!
  372. If you want gaussian, then the simplest way is to add 12 uniforms if
  373. accuracy is not that important.
  374. -- 
  375. Edward E.L. Mitchell           
  376. Mitchell & Gauthier Associates | Internet: mitchell@.mga.com
  377. [...]
  378.  
  379. ------------------------------------zzurv.f------------------------
  380.       subroutine zz urv(seed, output)
  381. c--------------------------------------random number generator based on
  382. c     algorithm proposed by d. h. lehmer. it is known formally as a
  383. c     prime modulus multiplicative linear congruential generator
  384. c     (pmmlcg), or less formally as a lehmer generator. derived from an
  385. c     implementation appearing in: park, stephen k. and miller, keith w.
  386. c     "random number generators: good ones are hard to find", commun.
  387. c     acm 31,10 (october, 1988), pp. 1192 - 1201.
  388. c
  389. c     as described in this paper, this implementation is based on
  390. c     schrage's method: schrage, l. "a more portable fortran random
  391. c     number generator". acm trans. math. softw. 5, 2(june 1979), pp.132
  392. c
  393. c     m        fixed prime modulus equal to (2**31 - 1)
  394. c     a        multiplier that produces a full period generating
  395. c              function f(z)=az mod m
  396. c     q        m div a
  397. c     r        m mod a
  398. c     test     can never take on a value which cannot be represented
  399. c              correctly with 32 bits (including sign)
  400. c     seed     any integer between 1 and (2**31 - 2)
  401. c     output   always REAL not DOUBLEPRECISION
  402. c
  403.       integer        seed    , hi      , test    , a       , q
  404.      .             , r
  405. c
  406.       parameter    ( a = 16807         , m = (2**30 - 1)*2 + 1
  407.      .             , q = m/a           , r = m - q*a
  408.      .             , floatm = m
  409.      .             )
  410. c
  411.       hi      = seed/q
  412.       test    = a*(seed - hi*q) - r*hi
  413.       if (test .gt. 0)then
  414.          seed = test
  415.       else
  416.          seed = test + m
  417.       endif
  418. c-----------------------------return result between zero and one
  419.       output  = seed/floatm
  420.       return
  421. c
  422.       end
  423. ------------------------------------zzgrv.f------------------------
  424.       subroutine zz grv(seed, output)
  425. c-----------------------------gaussian random variable. adds twelve
  426. c     uniform random numbers between 0 and 1.0 and subtracts average
  427. c     NOTE. output is always REAL, not DOUBLEPRECISION
  428. c
  429. c     copyright (c) mitchell and gauthier associates (1989)
  430. c     all rights reserved
  431. c
  432. c     inputs
  433. c
  434. c     seed     integer seed that will be changed
  435. c
  436. c     outputs
  437. c
  438. c     output   real random number (sum of 12 uniforms)
  439. c
  440.       integer        seed
  441. c
  442.       grv     = 0.0
  443.       do 110 j = 1, 12
  444. c-----------------------------use uniform random number generator
  445.       call zz urv(seed, urv)
  446.       grv     = grv + urv
  447.   110 continue
  448. c
  449. c-----------------------------subtract average so mean is zero
  450.       output  = grv - 6.0
  451.       return
  452. c
  453.       end
  454. ****************************************************************************
  455. Date: Wed, 16 Dec 92 11:39:26 -0700
  456. From: uesu03@giac1.oscs.montana.edu (Lou Glassy)
  457.  
  458. Ian, this is a random number generator I typed in from
  459. _Numerical Recipes_.  It's reasonable, and has a period
  460. of about 700 000 or so, ie the output numbers will repeat
  461. every 700 000 numbers or so.  This routine is standard
  462. Fortran-77, and should compile on any decent f77 compiler.
  463. I have tried it on MSDOS (BCF77), VMS/VAX FORTRAN, DEC/MIPS Fortran,
  464. HPUX Fortran, and IBM AIX Fortran, and it has worked on these
  465. OS/compiler combinations.
  466. [...]
  467. C=== delete everything above this line.
  468.  
  469.         REAL FUNCTION RAN2(IDUM)
  470. C returns a uniform random deviate between 0.0 and 1.0.
  471. C set idum to any negative value to initialize or
  472. C reinitialize the sequence.
  473. C source:  Numerical Recipes: The Art of Scientific Computing,
  474. C          by W. H. Press, 1989.
  475.  
  476. C persistent variables
  477.         SAVE IFF, IR, IY
  478.  
  479. C parameters
  480. C       inout
  481.         INTEGER IDUM
  482.  
  483. C constants
  484.         INTEGER M, IA, IC
  485.         REAL RM
  486.         PARAMETER (M=714025, IA=1366, IC=150889, RM=1.0/M)
  487.  
  488. C variables
  489.         INTEGER IFF, IR(97), IY, J
  490.         DATA IFF /0/
  491.  
  492. C begin
  493.         IF ((IDUM .LT. 0) .OR. (IFF .EQ. 0)) THEN
  494.            IFF = 1
  495.            IDUM = MOD(IC - IDUM, M)
  496.           
  497.            DO 11 J = 1, 97 
  498.               IDUM = MOD(IA * IDUM + IC, M)
  499.               IR(J) = IDUM
  500.  11        CONTINUE
  501.            IDUM = MOD(IA * IDUM + IC, M)
  502.            IY = IDUM
  503.         ENDIF
  504.  
  505. C here's where we start except on initialization.
  506.         J = 1 + (97 * IY) / M
  507.         IF ((J .GT. 97) .OR. (J .LT. 1)) PAUSE
  508.         IY = IR(J)
  509.         RAN2= IY * RM
  510.         IDUM = MOD(IA * IDUM + IC, M)
  511.         IR(J) = IDUM
  512.         
  513.         END
  514. ***************************************************************************
  515. Date: 18 Dec 92 20:34:42+0800
  516. From: Peter Hermann <ph@icavax.ica.uni-stuttgart.dbp.de>
  517.  
  518. Ian,
  519. it happened by chance, that the following mail
  520. arrived to me, just in time. Have fun and insight.
  521. merry christmas,
  522. Peter
  523. [...]
  524. 1.  Introduction
  525.  
  526. In designing a facility for the generation of pseudo-random numbers (hereafter
  527. called simply "random numbers") in Ada 9X, we have sought to balance utility
  528. and simplicity.  We do not offer all the bells and whistles someone might want
  529. or need, but we do offer the capabilities that are difficult to program
  530. correctly from scratch; other capabilities can be composed on top of these
  531. rather easily by the user, if required.
  532.  
  533. We present in section 2 the specification of a package providing the desired
  534. capabilities.  Section 3 discusses the design decisions leading to this
  535. specification, while section 4 discusses some other alternatives that might
  536. still be considered.  Section 5 discusses properties that the implementation
  537. must satisfy.  We conclude by inviting comments from reviewers.
  538.  
  539.  
  540. 2.  Specification
  541.  
  542. The specification of the random number facility for Ada 9X is as follows:
  543.  
  544.    package Random_Numbers is
  545.       
  546.       type Seed is <implementation-defined>;  -- but not private
  547.       Seed_Error : exception;                 -- see Set_Seed, below
  548.  
  549.       type Reset_Integer is
  550.          range <implementation-defined>;      -- see Reset, below
  551.  
  552.       generic
  553.          type Float_Type is digits <>;
  554.       package Generic_Generator is
  555.  
  556.          -- Instantiation of this generic package provides a random number
  557.          -- generator in each task; multiple instantiations provide multiple
  558.          -- generators.
  559.  
  560.          function Random return Float_Type;
  561.            -- Get the "next" random number, uniformly distributed on
  562.            -- [0.0, 1.0), from the current task's generator.
  563.  
  564.          procedure Reset (I : in Reset_Integer);
  565.            -- Set the state of the current task's generator to an
  566.            -- implementation-defined function of the integer I.
  567.  
  568.          procedure Reset;
  569.            -- Set the state of the current task's generator to an
  570.            -- implementation-defined function of the current date and time.
  571.  
  572.          procedure Get_Seed (S : out Seed);
  573.            -- Get the state of the current task's generator.
  574.  
  575.          procedure Set_Seed (S : in  Seed);
  576.            -- Set the state of the current task's generator to an explicit,
  577.            -- user-provided value; raises Seed_Error if S is unacceptable to
  578.            -- the implementation.
  579.  
  580.       end Generic_Generator;
  581.  
  582.    end Random_Numbers;
  583.  
  584.  
  585. 3.  Design decisions
  586.  
  587. As in many other languages, only one kind of distribution is provided, namely
  588. the uniform distribution.  More specifically, the random numbers generated by
  589. the facility are uniformly distributed on the semi-open interval [0.0, 1.0),
  590. and are delivered as values of a floating-point type chosen by the user.  Other
  591. intervals are easily obtained by scaling and translation:  if X is uniformly
  592. distributed on [0.0, 1.0), then a*X+b is uniformly distributed on [a, b).
  593. Integer values uniformly distributed on some interval are also easily obtained
  594. by appropriate scaling and conversion to integer, with post-conversion
  595. adjustment if rounding went "the wrong way."
  596.  
  597. Other distributions, such as the normal (Gaussian), Poisson, binomial, or
  598. exponential distributions, can be obtained from the uniform distribution by
  599. various standard techniques.  We focus our efforts on the capability most
  600. difficult to provide if it is not predefined, namely a reliable uniform random
  601. number generator.
  602.  
  603. Some algorithms naturally produce 0.0 among the numbers generated, and it is
  604. normal to include this value in the range of the random number generator.
  605. Mathematically, good algorithms exclude 1.0, but care must sometimes be
  606. exercised to avoid rounding a result close to 1.0 up to 1.0.  We could make the
  607. job simpler for implementors by including 1.0 in the specified range of random
  608. numbers but choose not to on account of the benefit to some applications of
  609. knowing that at least one of these extremes is never generated.  For example,
  610. if X is uniformly distributed on [0.0, 1.0), then -log(1.0 - X) is
  611. exponentially distributed with mean 1.0 and standard deviation 1.0, and it
  612. never receives an invalid argument.
  613.  
  614. A primary goal of the design of the random number facility for Ada 9X is the
  615. preservation of opportunities for innovation on the part of implementors, as
  616. the state of the art advances, while providing for a certain amount of
  617. portability of applications among implementations.  Thus, an algorithm is not
  618. prescribed, nor is the nature of the seed specified.  (The seed, which may be
  619. scalar or composite, embodies the state of a generator.  Technically, we should
  620. reserve "seed" to mean the initial state of a generator, but since a
  621. generator's current state may be though of as its initial state relative to the
  622. future sequence of outputs, we use seed to mean its current state.)  It is our
  623. intention to allow any of the following as implementations of the random number
  624. generator:
  625.  
  626.    o  good instances of a classical linear congruential generator, whose scalar
  627.       seed is an integer or, in some realizations, a floating-point number;
  628.  
  629.    o  combination generators, such as those of Wichmann and Hill or L'Ecuyer,
  630.       whose composite seed is a small vector;
  631.  
  632.    o  the more recent "subtract-with-borrow" or "add-with-carry" Fibonacci
  633.       generators of Marsaglia and Zaman that have phenomenally long periods,
  634.       but whose composite seed is a vector, often of twenty to a hundred
  635.       integer or floating-point components representing the lagged previous
  636.       outputs used in computing future outputs, plus another component
  637.       representing the next borrow or carry.
  638.  
  639. Some assurance of quality is provided by specifying minimal properties that the
  640. implementation must exhibit (see section 5).  Portable means of obtaining
  641. reproducible sequences of random numbers within a given implementation are
  642. provided, as are portable means of obtaining unique sequences of random numbers
  643. from one run to the next in a given implementation.  (Reproducible sequences
  644. are generally desired for application development and testing, while unique
  645. sequences are often wanted for production use of applications.)  The user must
  646. not expect to be able to obtain the same "reproducible" sequence of random
  647. numbers he or she has been accustomed to in one implementation upon switching
  648. to a different implementation, or when an implementation is upgraded by the
  649. vendor.
  650.  
  651. Generators have a default (implementation-defined) initial state, which
  652. provides for reproducibility of sequences across runs in simple applications.
  653. Unique sequences in different runs are obtained by replacing the default
  654. initial state with a time-dependent state (by calling the parameterless version
  655. of Reset before generating random numbers).
  656.  
  657. Normally, one does not need to manipulate the state of a generator (i.e., its
  658. seed) directly, but Get_Seed and Set_Seed are provided for those occasions
  659. when, in more advanced applications, it is desirable to do so.  For example,
  660. the current state of a generator can be obtained by a call to Get_Seed and
  661. saved in a file; the value retrieved from the file can be passed to Set_Seed in
  662. a subsequent run to resume the sequence from the previous stopping point.  This
  663. particular use does not require knowledge of the seed type, but other uses of
  664. Get_Seed and Set_Seed do and are inherently implementation dependent.  One
  665. example of such a non-portable use of Set_Seed is to obtain a reproducible
  666. sequence other than the one provided by default.  Another arises in
  667. applications in which different tasks have separate random number generators
  668. that must produce different, but reproducible, sequences.  The only general
  669. solution to this problem is to allow the user to compute an initial seed for
  670. the generator in each task, perhaps as a function of the current seed in the
  671. task's parent.  An example of a non-portable use of Get_Seed is its use in the
  672. simple printing of the current seed for debugging purposes.
  673.  
  674. The version of Reset with an integer parameter provides an alternative way to
  675. obtain a reproducible sequence other than the default sequence.  In contrast to
  676. using Set_Seed for that, Reset with an integer parameter is somewhat more
  677. portable though less general.  It is more portable only in the sense that the
  678. source text of some applications, for example those that prompt the user for a
  679. seed value, need not depend on the implementation.  It is less general in the
  680. sense that the possible values of a composite seed are far more numerous than
  681. those of a single integer, so only a subset of the possible states of a
  682. generator may be produced by calling Reset.  Every integer in the range of
  683. Reset_Integer should be acceptable to Reset.
  684.  
  685. The seed type is a visible type in order to support the convenient computation
  686. of seed values, when required.  Implementations are allowed to define other
  687. types in terms of which Seed is defined, as may be necessary when Seed is
  688. composite; they may also define Seed by a subtype declaration instead of a type
  689. declaration.
  690.  
  691. There are several different ways to enable separate tasks to have their own
  692. random number generators.  The method we have chosen has some limitations,
  693. discussed along with the alternatives in section 4, but provides within those
  694. limitations for the greatest simplicity of use.  Each instantiation of
  695. Generic_Generator provides each task with its own generator of random numbers,
  696. which is implicitly accessed by the operations Random, Reset, Get_Seed, and
  697. Set_Seed.  (They access the generator of the current task.)  This behavior can
  698. be implemented by appropriate instantiation of the predefined generic package
  699. Task_Identification.Per_Task_Attributes in the body of Generic_Generator (the
  700. seed becomes a per-task attribute).  Those single-task applications requiring
  701. multiple generators and those multitasking applications requiring multiple
  702. generators in some or all tasks can obtain them by instantiating
  703. Random_Numbers.Generic_Generator multiple times.
  704.  
  705. Some values of type Seed may be inappropriate for certain generators.  In some
  706. cases, inappropriate seed values cannot be excluded simply by the use of range
  707. constraints in the definition of Seed or its components.  The exception
  708. Seed_Error is provided for Set_Seed to use in signaling an attempt to set the
  709. state of a generator to an inappropriate value.  Implementations may prefer to
  710. avoid or reduce the possibility of inappropriate seed values, which arise
  711. largely through the use of floating-point seeds, by defining the seed type to
  712. be an integer or a composite of integer components, even when the internal
  713. state contains floating-point components (having integer or scaled integer
  714. values).
  715.  
  716. We do not provide a subprogram to fill a vector with random numbers in a single
  717. call.  On scalar computers, such a capability offers a reduction in the
  718. subprogram call overhead.  On vector computers, additional benefits might
  719. accrue by vectorizing the implementation, which is possible for some
  720. algorithms; the primary benefit on such computers, however, is the additional
  721. vectorization of the user's code that might be possible when, in a loop, random
  722. numbers are consumed from a vector rather than by calling a subprogram to
  723. generate each one.  In omitting this capability, we emphasize the minimal
  724. essential functionality of our random number facility.  Omitting it also keeps
  725. the generic formal part simple.  
  726.  
  727.  
  728. 4.  Alternatives
  729.  
  730. An alternative solution to the problem of obtaining different but reproducible
  731. sequences in different tasks, one that does not require knowledge of the seed
  732. type, is a procedure to "advance" a generator over some presumably large
  733. portion of its full period without generating the intervening elements.  This
  734. is relatively straightforward for linear congruential generators, but difficult
  735. or impossible for some of the other kinds of generators we wish to allow.
  736. Furthermore, obtaining many "different" sequences by systematically advancing
  737. their sequences by given amounts runs the risk of obtaining identical sequences
  738. offset in time, or, in the case of linear congruential generators, more weakly
  739. correlated sequences.  Thus, it seems desirable to give the user full latitude
  740. in deciding how to obtain reproducibly different sequences in different tasks,
  741. even though it means requiring the use of implementation-dependent procedures
  742. for doing so.
  743.  
  744. We have found in the literature a reference to a library at Queen's University,
  745. Belfast, whose subtract-with-borrow Fibonacci generator has a procedure for
  746. resetting the state of the generator from an integer, each value of which
  747. initiates a very long subsequence of the full period not overlapping with any
  748. other (in any practical sense).  We have not yet seen the theoretical basis for
  749. such a claim, and we do not know how to implement it ourselves.  Our Reset
  750. procedure (with an integer parameter) can provide exactly this functionality
  751. for appropriate generators; for such generators, at least, it provides a simple
  752. method of giving each task its own sequence of random numbers.
  753.  
  754. The simple printing of the current seed for debugging purposes could be made
  755. easier by something like an Image function that returns the state of a
  756. generator as a string according to some implementation-defined coding scheme.
  757. Indeed, initially we made the seed type private and contemplated Image and
  758. Value functions on seeds.  It does not seem likely that Image and Value would
  759. be suitable replacements for Get_Seed and Set_Seed; using them would, for many
  760. purposes, be inconvenient because of the need to code or decode the strings (in
  761. the case of a composite seed), and they would offer no real escape from the
  762. inherently implementation-defined nature of seeds.  We fear that they would
  763. give a false sense of being able to manipulate seeds portably, given that the
  764. implementation-defined characteristics of the interface would disappear from
  765. the specification and remain hidden away in the semantics.  We therefore omit
  766. Image and Value as not offering sufficient added benefit, given Get_Seed,
  767. Set_Seed, and a visible seed type.
  768.  
  769. The most difficult problem we faced in designing these facilities was their
  770. "packaging."  We could easily have done something different, and we are still
  771. not completely sure that we shouldn't.
  772.  
  773. The main attraction of our packaging method is the painless way in which each
  774. task is given its own generator of random numbers.  The user need not create
  775. objects in each task for the storage of the task's generator's state, and no
  776. extra parameters are needed to identify the generator being addressed in the
  777. various operations on generators; in particular, no parameters are passed to
  778. Random, which is therefore as easy to use in separate tasks (where separate
  779. generators are wanted) as in non-tasking applications.  It is anticipated that
  780. implementations will instantiate Task_Identification.Per_Task_Attributes
  781. internally to create a "slot" in each task for the task's random number
  782. generator's seed; this use of Per_Task_Attributes has been mentioned repeatedly
  783. during the design of that facility.
  784.  
  785. Some small number of applications might require multiple generators per task,
  786. or multiple generators in a single task.  They can be obtained by instantiating
  787. Random_Numbers.Generic_Generator multiple times.  This suffices if a fixed
  788. number of generators is needed, so that they can be addressed without using
  789. indexed names.  (If there are two generators per task, and the two
  790. instantiations of Generic_Generator are called, say, Velocity_Generator and
  791. Mass_Generator, then the random numbers from the two generators could be
  792. obtained by calling Velocity_Generator.Random and Mass_Generator.Random.)  Our
  793. scheme does not support applications requiring an arbitrary number of
  794. generators in a single task or in multiple tasks, where indexing is required.
  795. We do not view this as a serious limitation.
  796.  
  797. (There may be no overhead for random number generators in tasks that never
  798. invoke a random number operation; it depends on the implementation of
  799. Per_Task_Attributes.  That is, an instantiation of
  800. Random_Numbers.Generic_Generator does not necessarily cause the acquisition of
  801. space for the generator's seed; that happens, at least with the canonical
  802. implementation model of Per_Task_Attributes, only if and when an operation is
  803. first performed on a generator.  There is, however, a little extra overhead for
  804. using random number generators in our proposed scheme than in the alternatives
  805. discussed below.)
  806.  
  807. The most obvious way to allow the creation of arbitrary numbers of random
  808. number generators without the use of Per_Task_Attributes is to identify a
  809. generator with an object of type Seed.  A generator would be created by
  810. elaborating an object declaration for such an object.  (The declaration of the
  811. type Seed would be changed to specify the initial state of the generator as the
  812. initial value of objects of the type.)  The user would have the responsibility
  813. for creating generators in the quantity required, and in the just the places,
  814. i.e. tasks, required.  Operations on a particular generator would be designated
  815. by passing the seed as an "in" parameter to the operation ("in out" in the case
  816. of Random, which would have to become a procedure, since Random updates the
  817. state).  There would be no need for Get_Seed and Set_Seed operations.
  818.  
  819. We never contemplated actually making a seed the embodiment of a generator.
  820. Were we to follow something like the approach discussed immediately above, we
  821. would, instead, embody a generator in a separate type.  Our specification might
  822. be as follows:
  823.  
  824.    with System;
  825.    package Random_Numbers is
  826.  
  827.       type Generator is limited private;
  828.  
  829.       type Seed is <implementation-defined>;  -- but not private
  830.       Seed_Error : exception;
  831.  
  832.       type Reset_Integer is range <implementation-defined>;
  833.  
  834.       generic
  835.          type Float_Type is digits <>;
  836.       function Generic_Random (G : Generator) return Float_Type;
  837.  
  838.       procedure Get_Seed (G : in Generator; S : out Seed);
  839.       procedure Set_Seed (G : in Generator; S : in  Seed);
  840.       procedure Reset (G : in Generator; I : in Reset_Integer);
  841.       procedure Reset (G : in Generator);
  842.  
  843.    private
  844.  
  845.       type State is <implementation-defined>;  -- typically a record containing
  846.                                                -- a Seed component and maybe
  847.                                                -- other stuff
  848.       type Access_State is access State;
  849.       type Generator is new System.Controlled with record
  850.          S : Access_State := new State'(<implementation-defined>);
  851.       end record;
  852.       procedure Finalize (G : in out Generator);
  853.  
  854.    end Random_Numbers;
  855.  
  856. (Deriving Generator from System.Controlled allows finalization of generators
  857. and, thereby, the reclaiming of the storage allocated separately to their
  858. associated states.)
  859.  
  860. In this alternative, as in the proposal of sections 2 and 3, the state of a
  861. generator is not directly accessible.  That operations are performed on
  862. generators, not seeds, seems like the proper abstraction.  Get_Seed and
  863. Set_Seed play the same role as before in obtaining or changing the internal
  864. state of a generator (which now becomes a parameter to them).  Objects of type
  865. Seed would be declared, as in the original scheme, only if the user needs to
  866. obtain or save the state of a generator.  The validity check performed on a
  867. seed being provided to a generator remains part of the semantics of Set_Seed,
  868. where it is relevant.  If, in contrast, generators were directly associated
  869. with seeds, and created by creating objects of type Seed, and operated upon by
  870. operating on such objects, then Generic_Random would presumably have to
  871. validate the current seed each time a random number is requested (if seed
  872. validity needs to be checked), since the seed might have been changed by direct
  873. manipulation since the instantiation of Generic_Random was last called.  That
  874. would be intolerably expensive.
  875.  
  876. We would have to state that the generators provided by this alternative scheme
  877. are single-threaded; it would be an error to share them among (call them from)
  878. multiple tasks.  In the scheme proposed in sections 2 and 3, there is no need
  879. to make such a statement, since each task's generator can be called only by its
  880. own task.
  881.  
  882. In addition to being slightly more general than our original scheme, albeit
  883. slightly harder to use in simple applications, the alternative has two
  884. additional advantages.  One is that it can be implemented in Ada 83 (except for
  885. the reclamation of the storage occupied by a generator's state).  The other is
  886. that it can serve as the foundation of a higher-level abstraction that some
  887. users may wish to implement, using protected types -- that of a multi-threaded
  888. random number generator.  We do not consider the need for random number
  889. generators that can be called by multiple tasks (with appropriate
  890. serialization, of course) important enough to be predefined.  The
  891. nondeterministic nature of (the sequence of) calls to such generators would, in
  892. most cases, eliminate any possibility of reproducible behavior.  Nevertheless,
  893. it would be good to allow the advanced programmer the opportunity, at least, to
  894. create such a capability, if it is needed, out of more basic predefined
  895. components.  With the facility proposed in sections 2 and 3, it appears that
  896. providing such a capability requires the creation of a server task in which
  897. random numbers are generated, and with which other tasks must explicitly
  898. interact.  If control over the identity of generators were provided instead by
  899. the Generator type, the user could embed a Generator object in a protected
  900. object or protected type, as needed.
  901.  
  902. Are these advantages of the alternative scheme significant enough to warrant
  903. adopting it instead?  Reviewer comment is solicited on this question.
  904.  
  905. It has been suggested that some combination of both schemes be provided, so
  906. that simple applications can be served simply while not precluding more
  907. advanced applications.  That is, one could provide BOTH the Generator type (and
  908. operations on it) AND the inner generic package Generic_Generator.  (Text_IO
  909. has been cited as a model; there, I/O operations can be performed either on the
  910. "current default input or output file" or on arbitrary files.)  We have not
  911. actually proposed to do so because the resulting facility would have
  912. overlapping or redundant capabilities; most of the random number generators
  913. that would be needed, especially those in simple applications, could be created
  914. in either of two ways, which is confusing and unattractive.
  915.  
  916. It has been assumed that the need exists for the user to be able to specify the
  917. floating-point subtype of the random numbers that are delivered.  This is the
  918. reason why Random has become a generic function in the alternative proposal.
  919. The analogue of this in section 2 is the inner generic package,
  920. Generic_Generator, that contains the function Random.  There, however,
  921. genericity plays a further role: it is the means by which multiple generators
  922. are obtained in a task (more precisely, in each task).  Of course, the generic
  923. actual subtype used in the instantiation should have a range of at least
  924. 0.0 .. 1.0 and should provide "adequate" precision; too little could introduce
  925. repeated values into the output.  It may actually be preferable to standardize
  926. the result subtype of Generic_Random as Float, or let it be an
  927. implementation-defined floating-point subtype.  If this were to be done, then
  928. Generic_Random could revert to an ordinary function in the alternative
  929. proposal, and Generic_Generator could become a parameterless generic package in
  930. the original proposal; the user would generally have to convert the random
  931. numbers obtained to some application-dependent type.  (Evidence that this may
  932. be appropriate comes from our experimentation with different generator
  933. implementations; we observed that the conversion from implementation-dependent
  934. types appropriate to the algorithm to the user's type, denoted by Float_Type,
  935. occurs as the final step.)
  936.  
  937.  
  938. 5.  Properties required of implementations
  939.  
  940. Random number generators should have long periods.  It will be specified that
  941. implementations must exhibit a period of at least 2**31-2.  (Unfortunately, it
  942. is not practical for this property to be verified by a validation suite.)  An
  943. ultra-fast computer may be able to process applications for which this period
  944. is inadequate, in which case the vendor should consider using a
  945. subtract-with-borrow or add-with-carry Fibonacci generator.
  946.  
  947. There needs to be adequate assurance that the version of Reset that uses the
  948. current date and time will provide a unique sequence on two widely separated
  949. runs.  It will be specified that this procedure must reset the generator to
  950. different states when the interval between calls is at least one second and not
  951. greater than fifty years; a failure of this uniqueness property is allowed only
  952. when two calls are separated by exactly one hour and a return from daylight
  953. savings time to standard time intervenes.  Furthermore, the function that maps
  954. the current date and time into generator states should be a wildly varying
  955. function (i.e., one whose sensitivity to the components of the current date and
  956. time is greatest with respect to the second and least with respect to the
  957. year).  By the same token, the version of Reset that takes a user-supplied
  958. integer should map consecutive integers into generator states that initiate
  959. significantly different, and ideally uncorrelated, sequences.
  960.  
  961. The most important properties that implementations must exhibit are those
  962. related to the "randomness" (unpredictability to one not familiar with the
  963. algorithm) and uniformity of the generated numbers.  The general approach to
  964. uniformity testing is to formulate an experiment based on random sampling for
  965. which the expected outcome for a truly uniform random sample can be calculated,
  966. perform the experiment using the random number generator, calculate the
  967. chi-square value for the experimental observations, and then check that it is
  968. less than the chi-square value expected from theory (with some confidence like
  969. 95%).  Exact criteria are still being investigated, as are appropriate
  970. experiments.  The latter can be as simple as distributing the random numbers
  971. (or tuples of them) into cells of even width, which would be filled in equal
  972. number by truly uniform random numbers, or they can be more sophisticated.  One
  973. experiment that looks promising is the playing of a large number of "craps"
  974. games, with rolls of the dice simulated by the random number generator, for
  975. which measurements of wins and losses, game length, and the length of "passes"
  976. (runs of consecutive wins) can be tested against theoretical data for real
  977. dice.  This experiment is useful because correlations many dice rolls apart can
  978. affect the duration of a game; it can be combined with simple equidistribution
  979. tests on the outcomes of the dice rolls.  The literature describes a variety of
  980. experiments that have been used with some success in the past.
  981.  
  982.  
  983. Request for Review
  984.  
  985. Comments are solicited on any part of this proposal, but especially on the
  986. following questions:
  987.  
  988.    o  Should the approach be like that outlined in sections 2 and 3 (in which
  989.       the implementation is expected to use Per_Task_Attributes to give each
  990.       task a random number generator for each instantiation of
  991.       Generic_Generator), or should it be more like the alternative discussed
  992.       in section 4 (in which the user creates objects of type Generator in the
  993.       numbers and places desired), or should it be a combination of the two
  994.       approaches offering both simplified use and general use?
  995.  
  996.    o  Was the decision against providing vector output from the random number
  997.       generator correctly made and justified?
  998.  
  999.    o  Was the decision against making the seed type private, and against
  1000.       supporting a private type with Image and Value functions, correctly made
  1001.       and justified?
  1002.  
  1003.    o  Should the floating-point type of the random numbers be specified as
  1004.       Float, or specified by the implementation, instead of being selected by
  1005.       the user?
  1006.  
  1007.  
  1008. References
  1009.  
  1010. Publications that have proven useful during the preparation of this LSN include
  1011. the following:
  1012.  
  1013.    D. E. Knuth, "Seminumerical Algorithms" (vol. 2 of The Art of Computer
  1014.       Programming), Addison-Wesley, 1989.
  1015.  
  1016.    F. James, "A Review of Pseudorandom Number Generators," Computer Physics
  1017.       Communications 60:329-344, North-Holland, 1990.
  1018.  
  1019.    S. L. Anderson, "Random Number Generators on Vector Supercomputers and Other
  1020.       Advanced Architectures," SIAM Review 32(2):221-251, June 1990.
  1021.  
  1022.    G. Marsaglia and A. Zaman, "A New Class of Random Number Generators," Annals
  1023.       of Applied Probability 1(3):462-480, August 1991.
  1024.  
  1025.    Ada BCSLIB (Mathematical/Statistical Library), Report 20462-0519-R2, Boeing
  1026.       Computer Services, Seattle, 1990.
  1027.  
  1028.    B. A. Wichmann and I. D. Hill, "A Pseudo-Random Number Generator," Report
  1029.       DITC 6/82, National Physical Laboratory, Teddington, UK, June 1982.
  1030.  
  1031.    B. A. Wichmann and J. G. J. Meijerink, Report DITC 39/84, National Physical
  1032.       Laboratory, Teddington, UK, March 1984.
  1033.  
  1034.    P. Lecuyer, "Efficient and Portable Combined Random Number Generators,"
  1035.       CACM 31(6):742-749,774, June 1988.
  1036. *****************************************************************************
  1037. >>End included text<< 
  1038.