Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Floating point prng algorithm

vermue
Beginner
305 Views
0 Kudos
3 Replies
Olivier_C_
New Contributor I
304 Views
Quoting - vermue
I wrote a basic program to test this random generator. I'm looking for repeated shoots events at machine precision: they occur much less often than "random_number" (22 times in 1 million versus 248). They occur more often than the algorithm provided by Knuth in Numerical Recipes (0). This of course is a very basic test since a discrete one (as oposed to momentum computation).
I also test the speed of the program. Using a core of an Intel Q6600 at 2.4GHz, the "random_number" intrinsics takes slightly more times than the generator you refer to (1.42904s vs 1.38997s for 100 million shoots, Knuth takes 2.05887s). The new generator is thread safe, which is not the case of "random_number".
I join a small test program if you want to play with it.
So, in a nutshell, it sounds very good. I may use it for business.
Olivier.
$cat testprngAlvo.f90
! Check equal values:
! ifort -fp-speculation=safe -i8 -r8 -c testprngAlvo.f90 -o testprngAlvo.o && ifort -O3 -i8 -r8 -c funprngAlvo.f90 -o funprngAlvo.o && ifort -o a.testprngAlvo1 testprngAlvo.o funprngAlvo.o && ./a.testprngAlvo1 0 1
! Check speed:
! ifort -O3 -i8 -r8 -c testprngAlvo.f90 -o testprngAlvo.o && ifort -O3 -i8 -r8 -c funprngAlvo.f90 -o funprngAlvo.o && ifort -o a.testprngAlvo0 testprngAlvo.o funprngAlvo.o && ./a.testprngAlvo0 0 0
! First arg is 0(Alvo) or 1 (random_number), second arg is 0 (timing) or 1 (check)
program testprngAlvo
implicit none
real :: xn, s
integer :: n
integer :: ic1, ic2, ir, im
integer :: taille = 10000000 ! 10 millions for timing
real :: secl
integer :: method
integer :: performance
real :: getprngAlvo
integer idum
integer :: i,j, nloop
double PRECISION, dimension(:), allocatable :: tab
character*32 :: chaine
method = 0
performance = 0
call get_command_argument(1, chaine)
if (len_trim(chaine) > 0) then
read(chaine, *) method
endif
call get_command_argument(2, chaine)
if (len_trim(chaine) > 0) then
read(chaine, *) performance
endif
if (performance == 0) then
call system_clock(count=ic1, count_rate=ir, count_max=im)
if (method == 0) then
s = 0.5
do n=0, taille
xn = getprngAlvo(xn,n,s)
enddo
elseif(method == 1) then
do n=0, taille
call random_number(xn)
enddo
end if
call system_clock(ic2)
if (ic2 > ic1) then
secl = real(ic2-ic1)/real(ir)
else
secl = real(ic2+(im-ic1))/real(ir)
endif
write(6, FMT='("xn=",D25.16," time is",F14.6)') xn, secl
else
ALLOCATE(tab(taille/10))
nloop = 0
s = 0.5
n = 0
do i=1, taille/10 ! one million first numbers tested for uniqueness
if (method == 0) then
n = n + 1
xn = getprngAlvo(xn,n,s)
elseif(method == 1) then
call random_number(xn)
end if
tab(i) = xn
do j=1, i-1
if (tab(j) == tab(i)) then
write(6, FMT='("Looping=",I7,2(1X,I15),2(1X,D27.17))') nloop,i, j, tab(i), tab(j)
nloop = nloop + 1
endif
end do
enddo
write(6, FMT='("Looping=",I12," method=",I2)') nloop,method
endif
end program testprngAlvo
$ cat funprngAlvo.f90
function getprngAlvo(xn,n,s) result(y)
real, intent(in) :: xn
integer, intent(in) :: n
real, intent(in) :: s
real :: y
y = (n * xn + n*s +s * xn)-int(n * xn + n*s +s * xn)
end function getprngAlvo

0 Kudos
vermue
Beginner
304 Views
Olivier...

...thanks for your programe
I made some changes to speed up the algorithm (I think).
I do not now Fortran language.
Please correct me if i'm wrong.
The ideia is to put n as real, and cut some operations on the algotihm.
Teel me if this increase the speed.



! ifort -fp-speculation=safe -i8 -r8 -c testprngAlvo.f90 -o testprngAlvo.o && ifort -O3 -i8 -r8 -c funprngAlvo.f90 -o funprngAlvo.o && ifort -o a.testprngAlvo1 testprngAlvo.o funprngAlvo.o && ./a.testprngAlvo1 0 1
! Check speed:
! ifort -O3 -i8 -r8 -c testprngAlvo.f90 -o testprngAlvo.o && ifort -O3 -i8 -r8 -c funprngAlvo.f90 -o funprngAlvo.o && ifort -o a.testprngAlvo0 testprngAlvo.o funprngAlvo.o && ./a.testprngAlvo0 0 0
! First arg is 0(Alvo) or 1 (random_number), second arg is 0 (timing) or 1 (check)
program testprngAlvo
implicit none
real :: xn, s
real :: n !change here n pass to real
integer :: ic1, ic2, ir, im
integer :: taille = 10000000 ! 10 millions for timing
real :: secl
integer :: method
integer :: performance
real :: getprngAlvo
integer idum
integer :: i,j, nloop
double PRECISION, dimension(:), allocatable :: tab
character*32 :: chaine
method = 0
performance = 0
call get_command_argument(1, chaine)
if (len_trim(chaine) > 0) then
read(chaine, *) method
endif
call get_command_argument(2, chaine)
if (len_trim(chaine) > 0) then
read(chaine, *) performance
endif
if (performance == 0) then
call system_clock(count=ic1, count_rate=ir, count_max=im)
if (method == 0) then
s = 0.5
do n=0, taille
xn = getprngAlvo(xn,n,s)
enddo
elseif(method == 1) then
do n=0, taille
call random_number(xn)
enddo
end if
call system_clock(ic2)
if (ic2 > ic1) then
secl = real(ic2-ic1)/real(ir)
else
secl = real(ic2+(im-ic1))/real(ir)
endif
write(6, FMT='("xn=",D25.16," time is",F14.6)') xn, secl
else
ALLOCATE(tab(taille/10))
nloop = 0
s = 0.5
n = s ! change here n starts with the s value
do i=1, taille/10 ! one million first numbers tested for uniqueness
if (method == 0) then
n = n + 1
xn = getprngAlvo(xn,n,s)
elseif(method == 1) then
call random_number(xn)
end if
tab(i) = xn
do j=1, i-1
if (tab(j) == tab(i)) then
write(6, FMT='("Looping=",I7,2(1X,I15),2(1X,D27.17))') nloop,i, j, tab(i), tab(j)
nloop = nloop + 1
endif
end do
enddo
write(6, FMT='("Looping=",I12," method=",I2)') nloop,method
endif
end program testprngAlvo
$ cat funprngAlvo.f90
function getprngAlvo(xn,n,s) result(y)
real, intent(in) :: xn
real, intent(in) :: n !change here n pass to real
real, intent(in) :: s
real :: y
y = (n * xn +s)-int(n * xn +s) !change here
end function getprngAlvo
0 Kudos
Olivier_C_
New Contributor I
304 Views
I would not alter the program semantics just for speed increase.
The original program seems fast enough anyway.
If you do really need speed, I would suggest you use the MKL library made by Intel that is supposed to be very fast for getting a vector of random numbers.
Sincerely,

Olivier Cessenat.

0 Kudos
Reply