blob: 46ee86ccd2633bfb75fc8d88e18a283a95fe95d3 [file] [log] [blame]
!
! { dg-do run }
! { dg-options "-funsigned" }
!
! Modern Fortran rewrite of Marsaglia's 64-bit KISS PRNG.
! https://www.thecodingforums.com/threads/64-bit-kiss-rngs.673657/
!
module kissm
implicit none
private
public uk, kseed, kiss
integer, parameter :: uk = kind(1u_8) ! Check kind() works.
! Default seeds. Checks unsigned with parameter attribute.
unsigned(uk), parameter :: seed(4) = [ &
& 1234567890987654321u_uk, 362436362436362436u_uk, &
& 1066149217761810u_uk, 123456123456123456u_uk ]
! Seeds used during generation
unsigned(uk), save :: sd(4) = seed
contains
! Tests unsigned in an internal function.
function s(x)
unsigned(uk) s
unsigned(uk), intent(in) :: x
s = ishft(x, -63) ! Tests ishft
end function
! Poor seeding routine. Need to check v for entropy!
! Tests intent(in) and optional attributes.
! Tests ishftc() and array constructors.
subroutine kseed(v)
unsigned(uk), intent(in), optional :: v
if (present(v)) then
sd = seed + [ishftc(v,1), ishftc(v,15), ishftc(v,31), ishftc(v,44)]
else
sd = seed
end if
end subroutine kseed
function kiss()
unsigned(uk) kiss
unsigned(uk) m, t
integer k
! Test unsigned in a statement function
m(t, k) = ieor(t, ishft(t, k))
t = ishft(sd(1), 58) + sd(4)
if (s(sd(1)) == s(t)) then
sd(4) = ishft(sd(1), -6) + s(sd(1))
else
sd(4) = ishft(sd(1), -6) + 1u_uk - s(sd(1) + t)
endif
sd(1) = t + sd(1)
sd(2) = m(m(m(sd(2), 13), -17), 43)
sd(3) = 6906969069u_uk * sd(3) + 1234567u_uk
kiss = sd(1) + sd(2) + sd(3)
end function kiss
end module kissm
program testkiss
use kissm
integer, parameter :: n = 4
unsigned(uk) prn(4)
! Default sequence
unsigned(uk), parameter :: a(4) = [8932985056925012148u_uk, &
& 5710300428094272059u_uk, 18342510866933518593u_uk, &
& 14303636270573868250u_uk]
! Sequence with the seed 123412341234u_uk
unsigned(uk), parameter :: b(4) = [4002508872477953753u_uk, &
& 18025327658415290923u_uk, 16058856976144281263u_uk, &
& 11842224026193909403u_uk]
do i = 1, n
prn(i) = kiss()
end do
if (any(prn /= a)) stop 1
call kseed(123412341234u_uk)
do i = 1, n
prn(i) = kiss()
end do
if (any(prn /= b)) stop 2
call kseed()
do i = 1, n
prn(i) = kiss()
end do
if (any(prn /= a)) stop 3
end program testkiss