How about kiss05 random number generator?

Dear all,

I searched George Marsaglia as suggested by @Arjen , it seems George Marsaglia is one of kings of RNG,

have you used kiss RNG? Is it good?

Here perhaps is a very recent version,

https://web.mst.edu/~vojtat/class_5403/kiss05/rkiss05.f90

its test code is,

https://web.mst.edu/~vojtat/class_5403/kiss05/rtest.f90

I just wanted to put this kiss RNG into an module, and then use rtest.f90 to test.

However I met an error,

Severity Code Description Project File Line Suppression State
Error error LNK2019: unresolved external symbol RKISS05 referenced in function MAIN__ rtest.obj

It seems the rkiss05 function is not recognized in the main program. However, I think I have already put the code in rkiss05.f90 into a module called kiss, and I use kiss in the main program.

How can I fix this error? Thank you very much in advance!

The code is below, I only did

module kiss
implicit none
contains

 -- this part is just rkiss.f90 I did not change anything--

end module kiss

 --    then it is rtest.f90, I commented real(r8b), external  :: rkiss05  because it conflicts with use kiss--

Code is below,

module kiss
implicit none
contains
FUNCTION rkiss05()
 
integer,parameter      :: r8b= SELECTED_REAL_KIND(P=14,R=99)   ! 8-byte reals
integer,parameter      :: i4b= SELECTED_INT_KIND(8)            ! 4-byte integers 
real(r8b),parameter    :: am=4.656612873077392578d-10       ! multiplier 1/2^31

real(r8b)             :: rkiss05  
integer(i4b)          :: kiss
integer(i4b)          :: x,y,z,w              ! working variables for the four generators
common /kisscom/x,y,z,w 
  
x = 69069 * x + 1327217885
y= ieor (y, ishft (y, 13)); y= ieor (y, ishft (y, -17)); y= ieor (y, ishft (y, 5))
z = 18000 * iand (z, 65535) + ishft (z, - 16)
w = 30903 * iand (w, 65535) + ishft (w, - 16)
kiss = ishft(x + y + ishft (z, 16) + w , -1)
rkiss05=kiss*am
END FUNCTION rkiss05


SUBROUTINE kissinit(iinit)
integer,parameter      :: r8b= SELECTED_REAL_KIND(P=14,R=99)   ! 8-byte reals
integer,parameter     :: i4b= SELECTED_INT_KIND(8)            ! 4-byte integers 

integer(i4b) idum,ia,im,iq,ir,iinit
integer(i4b) k,x,y,z,w,c1,c2,c3,c4
real(r8b)    rkiss05,rdum
parameter (ia=16807,im=2147483647,iq=127773,ir=2836)
common /kisscom/x,y,z,w

!!! Test integer representation !!!
c1=-8
c1=ishftc(c1,-3)
!     print *,c1
if (c1.ne.536870911) then
    print *,'Nonstandard integer representation. Stoped.'
    stop
endif

idum=iinit
idum= abs(1099087573 * idum)               ! 32-bit LCG to shuffle seeds
if (idum.eq.0) idum=1
if (idum.ge.IM) idum=IM-1

k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then
    x=idum+1 
else 
    x=idum
endif
k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then 
    y=idum+1 
else 
    y=idum
endif
k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then
    z=idum+1 
else 
    z=idum
endif
k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then
    w=idum+1 
else 
    w=idum
endif

rdum=rkiss05()
  
return
end subroutine kissinit
end module kiss 


PROGRAM rtest
use kiss
implicit none
 
integer,parameter      :: r8b= SELECTED_REAL_KIND(P=14,R=99)   ! 8-byte reals
integer,parameter      :: i4b= SELECTED_INT_KIND(8)            ! 4-byte integers 

real(r8b)              :: x, sum, sum2, min, max
!real(r8b), external    :: rkiss05

call kissinit(1)    

print *,'Now printing the first 10 random numbers'
print *,'and the expected values (in brackets).'
print '(F12.9,A)',  rkiss05(),'  (0.100223257)'
print '(F12.9,A)',  rkiss05(),'  (0.654553312)'
print '(F12.9,A)',  rkiss05(),'  (0.533925296)'
print '(F12.9,A)',  rkiss05(),'  (0.129070464)'
print '(F12.9,A)',  rkiss05(),'  (0.846589457)'
print '(F12.9,A)',  rkiss05(),'  (0.938662817)'
print '(F12.9,A)',  rkiss05(),'  (0.388126970)'
print '(F12.9,A)',  rkiss05(),'  (0.415468296)'
print '(F12.9,A)',  rkiss05(),'  (0.321098742)'
print '(F12.9,A)',  rkiss05(),'  (0.572245760)'

stop      
END PROGRAM rtest
1 Like

Looks like you will have to fix the test program so that it references the RKISS05 from your MODULE KISS instead of an EXTERNAL RKISS05.

1 Like

@themos is right, but it is not only in the main program (the external attribute) but also in the routine kissinit. The error message I got after taking out the line “real(r8b), external :: rkiss05” was not caused by the test program, but by the line “real(r8b) :: rkiss05, rdum” in kissinit. A real puzzle so to say.

2 Likes

Indeed! That is the purpose of the IMPLICIT NONE(EXTERNAL) statement, to help catch these at compile time. At the moment though I can’t get any of GNU or Intel to issue a warning/error at compile time (NAG does not yet support these statements).

1 Like

So, how to make kiss05.f90 into a module?

As @Arjen says, you need to also remove the reference to rkiss05 in the declarations for kissinit in your module kiss:
i.e. change
real(r8b) rkiss05,rdum
to
real(r8b) rdum

3 Likes

Welcome, @Mark_Lewy!

2 Likes

Thank you very much indeed!

Now it works!

module kiss
implicit none
contains
FUNCTION rkiss05()
 
integer,parameter      :: r8b= SELECTED_REAL_KIND(P=14,R=99)   ! 8-byte reals
integer,parameter      :: i4b= SELECTED_INT_KIND(8)            ! 4-byte integers 
real(r8b),parameter    :: am=4.656612873077392578d-10       ! multiplier 1/2^31

real(r8b)             :: rkiss05  
integer(i4b)          :: kiss
integer(i4b)          :: x,y,z,w              ! working variables for the four generators
common /kisscom/x,y,z,w 
  
x = 69069 * x + 1327217885
y= ieor (y, ishft (y, 13)); y= ieor (y, ishft (y, -17)); y= ieor (y, ishft (y, 5))
z = 18000 * iand (z, 65535) + ishft (z, - 16)
w = 30903 * iand (w, 65535) + ishft (w, - 16)
kiss = ishft(x + y + ishft (z, 16) + w , -1)
rkiss05=kiss*am
END FUNCTION rkiss05


SUBROUTINE kissinit(iinit)
integer,parameter      :: r8b= SELECTED_REAL_KIND(P=14,R=99)   ! 8-byte reals
integer,parameter     :: i4b= SELECTED_INT_KIND(8)            ! 4-byte integers 

integer(i4b) idum,ia,im,iq,ir,iinit
integer(i4b) k,x,y,z,w,c1,c2,c3,c4
real(r8b) rdum
parameter (ia=16807,im=2147483647,iq=127773,ir=2836)
common /kisscom/x,y,z,w

!!! Test integer representation !!!
c1=-8
c1=ishftc(c1,-3)
!     print *,c1
if (c1.ne.536870911) then
    print *,'Nonstandard integer representation. Stoped.'
    stop
endif

idum=iinit
idum= abs(1099087573 * idum)               ! 32-bit LCG to shuffle seeds
if (idum.eq.0) idum=1
if (idum.ge.IM) idum=IM-1

k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then
    x=idum+1 
else 
    x=idum
endif
k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then 
    y=idum+1 
else 
    y=idum
endif
k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then
    z=idum+1 
else 
    z=idum
endif
k=(idum)/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum = idum + IM
if (idum.lt.1) then
    w=idum+1 
else 
    w=idum
endif

rdum=rkiss05()
  
return
end subroutine kissinit
end module kiss 


PROGRAM rtest
use kiss
implicit none
 
integer,parameter      :: r8b= SELECTED_REAL_KIND(P=14,R=99)   ! 8-byte reals
integer,parameter      :: i4b= SELECTED_INT_KIND(8)            ! 4-byte integers 

real(r8b)              :: x, sum, sum2, min, max
!real(r8b), external    :: rkiss05

call kissinit(1)    

print *,'Now printing the first 10 random numbers'
print *,'and the expected values (in brackets).'
print '(F12.9,A)',  rkiss05(),'  (0.100223257)'
print '(F12.9,A)',  rkiss05(),'  (0.654553312)'
print '(F12.9,A)',  rkiss05(),'  (0.533925296)'
print '(F12.9,A)',  rkiss05(),'  (0.129070464)'
print '(F12.9,A)',  rkiss05(),'  (0.846589457)'
print '(F12.9,A)',  rkiss05(),'  (0.938662817)'
print '(F12.9,A)',  rkiss05(),'  (0.388126970)'
print '(F12.9,A)',  rkiss05(),'  (0.415468296)'
print '(F12.9,A)',  rkiss05(),'  (0.321098742)'
print '(F12.9,A)',  rkiss05(),'  (0.572245760)'

stop      
END PROGRAM rtest

I think that the rule that applies here is the following, from Fortran 2018, Section 11.2.2, numbered item 8:

Two or more accessible entities, other than generic interfaces or defined operators, may have the same local identifier only if the identifier is not used.

In the original version of the program, the identifier rkiss05 is first used as a module function name and then declared as a local variable in the subroutine. At this point, the local identifier could be a variable or a function name. Later on within the subroutine, the identifier is used in an expression, which establishes it as an external function that is used, violating the rule quoted above.

You can verify this explanation by commenting out the statement with the function reference near the end of subroutine kissinit and then compiling.

2 Likes