| ! |
| ! { 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 |