📄 luxury.f90.txt
字号:
MODULE luxury
! Subtract-and-borrow random number generator proposed by
! Marsaglia and Zaman, implemented by F. James with the name
! RCARRY in 1991, and later improved by Martin Luescher
! in 1993 to produce "Luxury Pseudorandom Numbers".
! Fortran 77 coded by F. James, 1993
! References:
! M. Luscher, Computer Physics Communications 79 (1994) 100
! F. James, Computer Physics Communications 79 (1994) 111
! This Fortran 90 version is by Alan Miller (alan @ mel.dms.csiro.au)
! Latest revision - 11 September 1995
! LUXURY LEVELS.
! ------ ------ The available luxury levels are:
! level 0 (p=24): equivalent to the original RCARRY of Marsaglia
! and Zaman, very long period, but fails many tests.
! level 1 (p=48): considerable improvement in quality over level 0,
! now passes the gap test, but still fails spectral test.
! level 2 (p=97): passes all known tests, but theoretically still
! defective.
! level 3 (p=223): DEFAULT VALUE. Any theoretically possible
! correlations have very small chance of being observed.
! level 4 (p=389): highest possible luxury, all 24 bits chaotic.
!!!! ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!!!! Calling sequences for RANLUX: ++
!!!! CALL RANLUX (RVEC, LEN) returns a vector RVEC of LEN ++
!!!! 32-bit random floating point numbers between ++
!!!! zero (not included) and one (also not incl.). ++
!!!! CALL RLUXGO(LUX,INT,K1,K2) initializes the generator from ++
!!!! one 32-bit integer INT and sets Luxury Level LUX ++
!!!! which is integer between zero and MAXLEV, or if ++
!!!! LUX .GT. 24, it sets p=LUX directly. K1 and K2 ++
!!!! should be set to zero unless restarting at a break++
!!!! point given by output of RLUXAT (see RLUXAT). ++
!!!! CALL RLUXAT(LUX,INT,K1,K2) gets the values of four integers++
!!!! which can be used to restart the RANLUX generator ++
!!!! at the current point by calling RLUXGO. K1 and K2++
!!!! specify how many numbers were generated since the ++
!!!! initialization with LUX and INT. The restarting ++
!!!! skips over K1+K2*E9 numbers, so it can be long.++
!!!! A more efficient but less convenient way of restarting is by: ++
!!!! CALL RLUXIN(ISVEC) restarts the generator from vector ++
!!!! ISVEC of 25 32-bit integers (see RLUXUT) ++
!!!! CALL RLUXUT(ISVEC) outputs the current values of the 25 ++
!!!! 32-bit integer seeds, to be used for restarting ++
!!!! ISVEC must be dimensioned 25 in the calling program ++
!!!! ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
IMPLICIT NONE
INTEGER :: isdext(25)
INTEGER, PARAMETER :: maxlev = 4, lxdflt = 3, jsdflt = 314159265
INTEGER :: ndskip(0:maxlev) = (/ 0, 24, 73, 199, 365 /)
INTEGER :: igiga = 1000000000, i24 = 24, j24 = 10
REAL, PARAMETER :: twop12 = 4096.
INTEGER, PARAMETER :: itwo24 = 2**24, icons = 2147483563
INTEGER, SAVE :: next(24), luxlev = lxdflt, nskip, inseed, jseed
LOGICAL, SAVE :: notyet = .true.
INTEGER :: in24 = 0, kount = 0, mkount = 0
REAL, SAVE :: seeds(24), carry = 0., twom24, twom12
! default
! Luxury Level 0 1 2 *3* 4
! ndskip /0, 24, 73, 199, 365/
! Corresponds to p=24 48 97 223 389
! time factor 1 2 3 6 10 on slow workstation
! 1 1.5 2 3 5 on fast mainframe
! 1 1.5 2.5 5 8.5 on PC using LF90
PUBLIC notyet, i24, j24, carry, seeds, twom24, twom12, luxlev
PUBLIC nskip, ndskip, in24, next, kount, mkount, inseed
CONTAINS
SUBROUTINE ranlux(rvec, lenv)
IMPLICIT NONE
INTEGER, INTENT(IN) :: lenv
REAL, INTENT(OUT) :: rvec(lenv)
! Local variables
INTEGER :: i, k, lp, ivec, iseeds(24), isk
REAL :: uni
! NOTYET is .TRUE. if no initialization has been performed yet.
! Default Initialization by Multiplicative Congruential
IF (notyet) THEN
notyet = .false.
jseed = jsdflt
inseed = jseed
WRITE (6,'(A,I12)') ' RANLUX DEFAULT INITIALIZATION: ', jseed
luxlev = lxdflt
nskip = ndskip(luxlev)
lp = nskip + 24
in24 = 0
kount = 0
mkount = 0
WRITE (6,'(A,I2,A,I4)') ' RANLUX DEFAULT LUXURY LEVEL = ', luxlev, &
' p =', lp
twom24 = 1.
DO i = 1, 24
twom24 = twom24 * 0.5
k = jseed / 53668
jseed = 40014 * (jseed-k*53668) - k * 12211
IF (jseed.LT.0) jseed = jseed + icons
iseeds(i) = MOD(jseed,itwo24)
END DO
twom12 = twom24 * 4096.
DO i = 1, 24
seeds(i) = REAL(iseeds(i)) * twom24
next(i) = i - 1
END DO
next(1) = 24
i24 = 24
j24 = 10
carry = 0.
IF (seeds(24).EQ.0.) carry = twom24
END IF
! The Generator proper: "Subtract-with-borrow",
! as proposed by Marsaglia and Zaman,
! Florida State University, March, 1989
DO ivec = 1, lenv
uni = seeds(j24) - seeds(i24) - carry
IF (uni.LT.0.) THEN
uni = uni + 1.0
carry = twom24
ELSE
carry = 0.
END IF
seeds(i24) = uni
i24 = next(i24)
j24 = next(j24)
rvec(ivec) = uni
! small numbers (with less than 12 "significant" bits) are "padded".
IF (uni.LT.twom12) THEN
rvec(ivec) = rvec(ivec) + twom24 * seeds(j24)
! and zero is forbidden in case someone takes a logarithm
IF (rvec(ivec).EQ.0.) rvec(ivec) = twom24 * twom24
END IF
! Skipping to luxury. As proposed by Martin Luscher.
in24 = in24 + 1
IF (in24.EQ.24) THEN
in24 = 0
kount = kount + nskip
DO isk = 1, nskip
uni = seeds(j24) - seeds(i24) - carry
IF (uni.LT.0.) THEN
uni = uni + 1.0
carry = twom24
ELSE
carry = 0.
END IF
seeds(i24) = uni
i24 = next(i24)
j24 = next(j24)
END DO
END IF
END DO
kount = kount + lenv
IF (kount.GE.igiga) THEN
mkount = mkount + 1
kount = kount - igiga
END IF
RETURN
END SUBROUTINE ranlux
! Subroutine to input and float integer seeds from previous run
SUBROUTINE rluxin
! the following IF BLOCK added by Phillip Helbig, based on conversation
! with Fred James; an equivalent correction has been published by James.
IMPLICIT NONE
! Local variables
INTEGER :: i, isd
IF (notyet) THEN
WRITE (6,'(A)') ' Proper results ONLY with initialisation from 25 ', &
'integers obtained with RLUXUT'
notyet = .false.
END IF
twom24 = 1.
DO i = 1, 24
next(i) = i - 1
twom24 = twom24 * 0.5
END DO
next(1) = 24
twom12 = twom24 * 4096.
WRITE (6,'(A)') ' FULL INITIALIZATION OF RANLUX WITH 25 INTEGERS:'
WRITE (6,'(5X,5I12)') isdext
DO i = 1, 24
seeds(i) = REAL(isdext(i)) * twom24
END DO
carry = 0.
IF (isdext(25).LT.0) carry = twom24
isd = ABS(isdext(25))
i24 = MOD(isd,100)
isd = isd / 100
j24 = MOD(isd,100)
isd = isd / 100
in24 = MOD(isd,100)
isd = isd / 100
luxlev = isd
IF (luxlev.LE.maxlev) THEN
nskip = ndskip(luxlev)
WRITE (6,'(A,I2)') ' RANLUX LUXURY LEVEL SET BY RLUXIN TO: ', luxlev
ELSE IF (luxlev.GE.24) THEN
nskip = luxlev - 24
WRITE (6,'(A,I5)') ' RANLUX P-VALUE SET BY RLUXIN TO:', luxlev
ELSE
nskip = ndskip(maxlev)
WRITE (6,'(A,I5)') ' RANLUX ILLEGAL LUXURY RLUXIN: ', luxlev
luxlev = maxlev
END IF
inseed = -1
RETURN
END SUBROUTINE rluxin
! Subroutine to ouput seeds as integers
SUBROUTINE rluxut
IMPLICIT NONE
! Local variables
INTEGER :: i
DO i = 1, 24
isdext(i) = INT(seeds(i)*twop12*twop12)
END DO
isdext(25) = i24 + 100 * j24 + 10000 * in24 + 1000000 * luxlev
IF (carry.GT.0.) isdext(25) = -isdext(25)
RETURN
END SUBROUTINE rluxut
! Subroutine to output the "convenient" restart point
SUBROUTINE rluxat(lout, inout, k1, k2)
IMPLICIT NONE
INTEGER, INTENT(OUT) :: lout, inout, k1, k2
lout = luxlev
inout = inseed
k1 = kount
k2 = mkount
RETURN
END SUBROUTINE rluxat
! Subroutine to initialize from one or three integers
SUBROUTINE rluxgo(lux, ins, k1, k2)
IMPLICIT NONE
INTEGER, INTENT(IN) :: lux, ins, k1, k2
! Local variables
INTEGER :: ilx, i, iouter, iseeds(24), isk, k, inner, izip, izip2
REAL :: uni
IF (lux.LT.0) THEN
luxlev = lxdflt
ELSE IF (lux.LE.maxlev) THEN
luxlev = lux
ELSE IF (lux.LT.24.OR.lux.GT.2000) THEN
luxlev = maxlev
WRITE (6,'(A,I7)') ' RANLUX ILLEGAL LUXURY RLUXGO: ', lux
ELSE
luxlev = lux
DO ilx = 0, maxlev
IF (lux.EQ.ndskip(ilx)+24) luxlev = ilx
END DO
END IF
IF (luxlev.LE.maxlev) THEN
nskip = ndskip(luxlev)
WRITE (6,'(A,I2,A,I4)') ' RANLUX LUXURY LEVEL SET BY RLUXGO :', luxlev, &
' P=', nskip + 24
ELSE
nskip = luxlev - 24
WRITE (6,'(A,I5)') ' RANLUX P-VALUE SET BY RLUXGO TO:', luxlev
END IF
in24 = 0
IF (ins.LT.0) WRITE (6,'(A)') &
' Illegal initialization by RLUXGO, negative input seed'
IF (ins.GT.0) THEN
jseed = ins
WRITE (6,'(A,3I12)') ' RANLUX INITIALIZED BY RLUXGO FROM SEEDS', jseed, k1, k2
ELSE
jseed = jsdflt
WRITE (6,'(A)') ' RANLUX INITIALIZED BY RLUXGO FROM DEFAULT SEED'
END IF
inseed = jseed
notyet = .false.
twom24 = 1.
DO i = 1, 24
twom24 = twom24 * 0.5
k = jseed / 53668
jseed = 40014 * (jseed-k*53668) - k * 12211
IF (jseed.LT.0) jseed = jseed + icons
iseeds(i) = MOD(jseed,itwo24)
END DO
twom12 = twom24 * 4096.
DO i = 1, 24
seeds(i) = REAL(iseeds(i)) * twom24
next(i) = i - 1
END DO
next(1) = 24
i24 = 24
j24 = 10
carry = 0.
IF (seeds(24).EQ.0.) carry = twom24
! If restarting at a break point, skip K1 + IGIGA*K2
! Note that this is the number of numbers delivered to
! the user PLUS the number skipped (if luxury .GT. 0).
kount = k1
mkount = k2
IF (k1+k2.NE.0) THEN
DO iouter = 1, k2 + 1
inner = igiga
IF (iouter.EQ.k2+1) inner = k1
DO isk = 1, inner
uni = seeds(j24) - seeds(i24) - carry
IF (uni.LT.0.) THEN
uni = uni + 1.0
carry = twom24
ELSE
carry = 0.
END IF
seeds(i24) = uni
i24 = next(i24)
j24 = next(j24)
END DO
END DO
! Get the right value of IN24 by direct calculation
in24 = MOD(kount,nskip+24)
IF (mkount.GT.0) THEN
izip = MOD(igiga, nskip+24)
izip2 = mkount * izip + in24
in24 = MOD(izip2, nskip+24)
END IF
! Now IN24 had better be between zero and 23 inclusive
IF (in24.GT.23) THEN
WRITE (6,'(A/A,3I11,A,I5)') &
' Error in RESTARTING with RLUXGO:', ' The values', ins, &
k1, k2, ' cannot occur at luxury level', luxlev
in24 = 0
END IF
END IF
RETURN
END SUBROUTINE rluxgo
END MODULE luxury
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -