source: trunk/SpectralModelF90/PROJECTS/trivial/zufall.f @ 6

Last change on this file since 6 was 6, checked in by xlvlod, 18 years ago

import initial from SVN_BASE_TRUNK

File size: 13.7 KB
Line 
1* README for zufall random number package
2* ------ --- ------ ------ ------ -------
3* This package contains a portable random number generator set
4* for: uniform (u in [0,1)), normal (<g> = 0, <g^2> = 1), and
5* Poisson distributions. The basic module, the uniform generator,
6* uses a lagged Fibonacci series generator:
7* 
8*               t    = u(n-273) + u(n-607)
9*               u(n) = t - float(int(t))
10* 
11* where each number generated, u(k), is floating point. Since
12* the numbers are floating point, the left end boundary of the
13* range contains zero. This package is nearly portable except
14* for the following. (1) It is written in lower case, (2) the
15* test package contains a timer (second) which is not portable,
16* and (3) there are cycle times (in seconds) in data statements 
17* for NEC SX-3, Fujitsu VP2200, and Cray Y-MP. Select your 
18* favorite and comment out the others. Replacement functions 
19* for 'second' are included - comment out the others. Otherwise 
20* the package is portable and returns the same set of floating 
21* point numbers up to word precision on any machine. There are 
22* compiler directives ($cdir for Cray, *vdir for SX-3, and VOCL 
23* for Fujitsu VP2200) which should be otherwise ignored.
24* 
25* To compile this beast, note that all floating point numbers
26* are declared 'double precision'. On Cray X-MP, Y-MP, and C-90
27* machines, use the cft77 (cf77) option -dp to run this in 64
28* bit mode (not 128 bit double).
29* 
30* External documentation, "Lagged Fibonacci Random Number Generators
31* for the NEC SX-3," is to be published in the International
32* Journal of High Speed Computing (1994). Otherwise, ask the
33* author: 
34* 
35*          W. P. Petersen 
36*          IPS, RZ F-5
37*          ETHZ
38*          CH 8092, Zurich
39*          Switzerland
40* 
41* e-mail:  wpp@ips.ethz.ch.
42* 
43* The package contains the following routines:
44* 
45* ------------------------------------------------------
46* UNIFORM generator routines:
47* 
48*       subroutine zufalli(seed)
49*       integer seed
50* c initializes common block containing seeds. if seed=0,
51* c the default value is 1802.
52* 
53*       subroutine zufall(n,u)
54*       integer n
55*       double precision u(n)
56* c returns set of n uniforms u(1), ..., u(n).
57* 
58*       subroutine zufallsv(zusave)
59*       double precision zusave(608)
60* c saves buffer and pointer in zusave, for later restarts
61* 
62*       subroutine zufallrs(zusave)
63*       double precision zusave(608)
64* c restores seed buffer and pointer from zusave
65* ------------------------------------------------------
66* 
67* NORMAL generator routines:
68* 
69*       subroutine normalen(n,g)
70*       integer n
71*       double precision g(n)
72* c returns set of n normals g(1), ..., g(n) such that
73* c mean <g> = 0, and variance <g**2> = 1.
74* 
75*       subroutine normalsv(normsv)
76*       double precision normsv(1634)
77* c saves zufall seed buffer and pointer in normsv
78* c buffer/pointer for normalen restart also in normsv
79* 
80*       subroutine normalrs(normsv)
81*       double precision normsv(1634)
82* c restores zufall seed buffer/pointer and 
83* c buffer/pointer for normalen restart from normsv
84* ------------------------------------------------------
85* 
86* POISSON generator routine:
87* 
88*       subroutine fische(n,mu,q)
89*       integer n,q(n)
90*       double precision mu
91* c returns set of n integers q, with poisson
92* c distribution, density p(q,mu) = exp(-mu) mu**q/q!
93* c 
94* c USE zufallsv and zufallrs for stop/restart sequence
95* c
96      subroutine zufall(n,a)
97      implicit none
98c
99c portable lagged Fibonacci series uniform random number
100c generator with "lags" -273 und -607:
101c
102c       t    = u(i-273)+buff(i-607)  (floating pt.)
103c       u(i) = t - float(int(t))
104c
105c W.P. Petersen, IPS, ETH Zuerich, 19 Mar. 92
106c
107      double precision a(*)
108      double precision buff(607)
109      double precision t
110      integer i,k,ptr,VL,k273,k607
111      integer buffsz,nn,n,left,q,qq
112      integer aptr,aptr0,bptr
113c
114      common /klotz0/buff,ptr
115      data buffsz/607/
116c
117      aptr = 0
118      nn   = n
119c
1201     continue
121c
122      if(nn .le. 0) return
123c
124c factor nn = q*607 + r
125c
126      q    = (nn-1)/607
127      left = buffsz - ptr
128c
129      if(q .le. 1) then
130c
131c only one or fewer full segments
132c
133         if(nn .lt. left) then
134            do 2 i=1,nn
135               a(i+aptr) = buff(ptr+i)
1362           continue
137            ptr  = ptr + nn
138            return
139         else
140            do 3 i=1,left
141               a(i+aptr) = buff(ptr+i)
1423           continue
143            ptr  = 0
144            aptr = aptr + left
145            nn   = nn - left
146c  buff -> buff case
147            VL   = 273
148            k273 = 334
149            k607 = 0
150            do 4 k=1,3
151cdir$ ivdep
152*vdir nodep
153*VOCL LOOP, TEMP(t), NOVREC(buff)
154               do 5 i=1,VL
155                  t            = buff(k273+i) + buff(k607+i)
156                  buff(k607+i) = t - float(int(t))
1575              continue
158               k607 = k607 + VL
159               k273 = k273 + VL
160               VL   = 167
161               if(k.eq.1) k273 = 0
1624           continue
163c
164            goto 1
165         endif
166      else
167c
168c more than 1 full segment
169c 
170          do 6 i=1,left
171             a(i+aptr) = buff(ptr+i)
1726         continue
173          nn   = nn - left
174          ptr  = 0
175          aptr = aptr+left
176c 
177c buff -> a(aptr0)
178c 
179          VL   = 273
180          k273 = 334
181          k607 = 0
182          do 7 k=1,3
183             if(k.eq.1)then
184*VOCL LOOP, TEMP(t)
185                do 8 i=1,VL
186                   t         = buff(k273+i) + buff(k607+i)
187                   a(aptr+i) = t - float(int(t))
1888               continue
189                k273 = aptr
190                k607 = k607 + VL
191                aptr = aptr + VL
192                VL   = 167
193             else
194cdir$ ivdep
195*vdir nodep
196*VOCL LOOP, TEMP(t)
197                do 9 i=1,VL
198                   t         = a(k273+i) + buff(k607+i)
199                   a(aptr+i) = t - float(int(t))
2009               continue
201                k607 = k607 + VL
202                k273 = k273 + VL
203                aptr = aptr + VL
204             endif
2057         continue
206          nn = nn - 607
207c
208c a(aptr-607) -> a(aptr) for last of the q-1 segments
209c
210          aptr0 = aptr - 607
211          VL    = 607
212c
213*vdir novector
214          do 10 qq=1,q-2
215             k273 = 334 + aptr0
216cdir$ ivdep
217*vdir nodep
218*VOCL LOOP, TEMP(t), NOVREC(a)
219             do 11 i=1,VL
220                t         = a(k273+i) + a(aptr0+i)
221                a(aptr+i) = t - float(int(t))
22211           continue
223             nn    = nn - 607
224             aptr  = aptr + VL
225             aptr0 = aptr0 + VL
22610        continue
227c
228c a(aptr0) -> buff, last segment before residual
229c
230          VL   = 273
231          k273 = 334 + aptr0
232          k607 = aptr0
233          bptr = 0
234          do 12 k=1,3
235             if(k.eq.1) then
236*VOCL LOOP, TEMP(t)
237                do 13 i=1,VL
238                   t            = a(k273+i) + a(k607+i)
239                   buff(bptr+i) = t - float(int(t))
24013              continue
241                k273 = 0
242                k607 = k607 + VL
243                bptr = bptr + VL
244                VL   = 167
245             else
246cdir$ ivdep
247*vdir nodep
248*VOCL LOOP, TEMP(t), NOVREC(buff)
249                do 14 i=1,VL
250                   t            = buff(k273+i) + a(k607+i)
251                   buff(bptr+i) = t - float(int(t))
25214              continue
253                k607 = k607 + VL
254                k273 = k273 + VL
255                bptr = bptr + VL
256             endif
25712        continue
258          goto 1
259      endif
260      end
261c
262      subroutine zufalli(seed)
263      implicit none
264c
265c  generates initial seed buffer by linear congruential
266c  method. Taken from Marsaglia, FSU report FSU-SCRI-87-50
267c  variable seed should be 0 < seed <31328
268c
269      integer seed
270      integer ptr
271      double precision s,t
272      double precision buff(607)
273      integer ij,kl,i,ii,j,jj,k,l,m
274      common /klotz0/buff,ptr
275      data ij/1802/,kl/9373/
276c
277      if(seed.ne.0) ij = seed
278c
279      i = mod(ij/177,177) + 2
280      j = mod(ij,177) + 2
281      k = mod(kl/169,178) + 1
282      l = mod(kl,169)
283      do 1 ii=1,607
284         s = 0.0
285         t = 0.5
286         do 2 jj=1,24
287            m = mod(mod(i*j,179)*k,179)
288            i = j
289            j = k
290            k = m
291            l = mod(53*l+1,169)
292            if(mod(l*m,64).ge.32) s = s+t
293            t = .5*t
2942        continue
295         buff(ii) = s
2961     continue
297      return
298      end
299c
300      subroutine zufallsv(svblk)
301      implicit none
302c
303c  saves common blocks klotz0, containing seeds and
304c  pointer to position in seed block. IMPORTANT: svblk must be
305c  dimensioned at least 608 in driver. The entire contents
306c  of klotz0 (pointer in buff, and buff) must be saved.
307c
308      double precision buff(607)
309      integer ptr,i
310      double precision svblk(*)
311      common /klotz0/buff,ptr
312c
313      svblk(1) = ptr
314      do 1 i=1,607
315         svblk(i+1) = buff(i)
3161     continue
317c
318      return
319      end
320      subroutine zufallrs(svblk)
321      implicit none
322c
323c  restores common block klotz0, containing seeds and pointer
324c  to position in seed block. IMPORTANT: svblk must be
325c  dimensioned at least 608 in driver. The entire contents
326c  of klotz0 must be restored.
327c
328      double precision buff(607)
329      integer i,ptr
330      double precision svblk(*)
331      common /klotz0/buff,ptr
332c
333      ptr = svblk(1)
334      do 1 i=1,607
335         buff(i) = svblk(i+1)
3361     continue
337c
338      return
339      end
340      subroutine normalen(n,x)
341      implicit none
342c
343c Box-Muller method for Gaussian random numbers
344c
345      double precision x(*)
346      double precision xbuff(1024)
347      integer i,ptr,xptr,first
348      integer buffsz,nn,n,left 
349      common /klotz1/xbuff,first,xptr
350      data buffsz/1024/
351c
352      nn   = n
353      if(nn .le. 0) return
354      if(first.eq.0)then
355         call normal00
356         first = 1
357      endif
358      ptr = 0
359c
3601     continue
361      left = buffsz - xptr
362      if(nn .lt. left) then
363         do 2 i=1,nn
364            x(i+ptr) = xbuff(xptr+i)
3652        continue
366         xptr = xptr + nn
367         return
368      else
369         do 3 i=1,left
370            x(i+ptr) = xbuff(xptr+i)
3713        continue
372         xptr = 0
373         ptr  = ptr+left
374         nn   = nn - left
375         call normal00
376         goto 1
377      endif
378      end
379      subroutine normal00
380      implicit none
381      double precision pi,twopi
382      parameter(pi=3.141592653589793)
383      double precision xbuff(1024),r1,r2,t1,t2
384      integer first,xptr,i
385      common /klotz1/xbuff,first,xptr
386c
387      twopi = 2.*pi
388      call zufall(1024,xbuff)
389*VOCL LOOP, TEMP(r1,r2,t1,t2), NOVREC(xbuff)
390      do 1 i=1,1024,2
391         r1         = twopi*xbuff(i)
392         t1         = cos(r1)
393         t2         = sin(r1)
394         r2         = sqrt(-2.*log(1.-xbuff(i+1)))
395         xbuff(i)   = t1*r2
396         xbuff(i+1) = t2*r2
3971     continue
398c
399      return
400      end
401      subroutine normalsv(svbox)
402      implicit none
403c
404c  saves common block klotz0 containing buffers
405c  and pointers. IMPORTANT: svbox must be dimensioned at 
406c  least 1634 in driver. The entire contents of blocks 
407c  klotz0 (via zufallsv) and klotz1 must be saved.
408c
409      double precision buff(607)
410      integer i,k,ptr
411      double precision xbuff(1024)
412      integer xptr,first
413      double precision svbox(*)
414      common /klotz0/buff,ptr
415      common /klotz1/xbuff,first,xptr
416c
417      if(first.eq.0)then
418         print *,' ERROR in normalsv, save of unitialized block'
419      endif
420c
421c  save zufall block klotz0
422c
423      call zufallsv(svbox)
424c
425      svbox(609) = first
426      svbox(610) = xptr
427      k = 610
428      do 1 i=1,1024
429         svbox(i+k) = xbuff(i)
4301     continue
431c
432      return
433      end
434      subroutine normalrs(svbox)
435      implicit none
436c
437c  restores common blocks klotz0, klotz1 containing buffers
438c  and pointers. IMPORTANT: svbox must be dimensioned at 
439c  least 1634 in driver. The entire contents
440c  of klotz0 and klotz1 must be restored.
441c
442      double precision buff(607)
443      integer ptr
444      double precision xbuff(1024)
445      integer i,k,xptr,first
446      double precision svbox(*)
447      common /klotz0/buff,ptr
448      common /klotz1/xbuff,first,xptr
449c
450c restore zufall blocks klotz0 and klotz1
451c
452      call zufallrs(svbox)
453      first = svbox(609)
454      if(first.eq.0)then
455         print *,' ERROR in normalsv, restoration of unitialized block'
456      endif
457      xptr  = svbox(610)
458      k = 610
459      do 1 i=1,1024
460         xbuff(i) = svbox(i+k)
4611     continue
462c
463      return
464      end
465      subroutine fische(n,mu,p)
466      implicit none
467      integer p(*)
468      integer indx(1024)
469      integer n,i,ii,jj,k,left,nl0,nsegs,p0
470      double precision u(1024),q(1024)
471      double precision q0,pmu,mu
472c
473c Poisson generator for distribution function of p's:
474c
475c    q(mu,p) = exp(-mu) mu**p/p!
476c
477c initialize arrays, pointers
478c
479      if (n.le.0) return
480c
481      pmu = exp(-mu)
482      p0  = 0
483c
484      nsegs = (n-1)/1024
485      left  = n - nsegs*1024
486      nsegs = nsegs + 1
487      nl0   = left
488c
489      do 2 k = 1,nsegs
490c
491         do 3 i=1,left
492            indx(i)    = i
493            p(p0+i)    = 0
494            q(i)       = 1.0
4953        continue
496c
497c Begin iterative loop on segment of p's
498c
4991        continue
500c
501c Get the needed uniforms
502c
503         call zufall(left,u)
504c
505         jj = 0
506c
507cdir$ ivdep
508*vdir nodep
509*VOCL LOOP, TEMP(ii,q0), NOVREC(indx,p,q)
510         do 4 i=1,left
511            ii    = indx(i)
512            q0    = q(ii)*u(i)
513            q(ii) = q0
514            if( q0.gt.pmu ) then
515               jj       = jj + 1
516               indx(jj) = ii
517               p(p0+ii) = p(p0+ii) + 1
518            endif
5194        continue
520c
521c any left in this segment?
522c
523         left = jj
524         if(left.gt.0)then
525            goto 1
526         endif
527c
528         p0    = p0 + nl0
529         nl0   = 1024
530         left  = 1024
531c
5322     continue
533c
534      return
535      end
536c
537      block data
538      implicit none
539c
540c globally accessable, compile-time initialized data
541c
542      integer ptr,xptr,first
543      double precision buff(607),xbuff(1024)
544      common /klotz0/buff,ptr
545      common /klotz1/xbuff,first,xptr
546      data ptr/0/,xptr/0/,first/0/
547      end
Note: See TracBrowser for help on using the repository browser.