TEMAIII: TEMAS COMPLEMENTARIOS

Anuncio
TEMAIII: TEMAS COMPLEMENTARIOS
1.- Generación de números aleatorios.
Algoritmo : método del residuo (linear congruental method)
In+1= (A * In + C) mod M ≡ Resto ( (A * In + C) / M )
Ejemplo: A=4, I1=3, C=1, M=9
I1=3
I2=resto ( (4*3 + 1)/9 ) = 4
I3=resto ( (4*4 + 1)/9 ) = 8
I4=resto ( (4*8 + 1)/9 ) = 6
I5=resto ( (4*6 + 1)/9 ) = 7
I6=resto ( (4*7 + 1)/9 ) = 2
I7=resto ( (4*2 + 1)/9 ) = 0
I8=resto ( (4*0 + 1)/9 ) = 1
I9=resto ( (4*1 + 1)/9 ) = 5
A partir de aquí se repite la secuencia:
I10=resto ( (4*5 + 1)/9 ) = 3
………………………….
Veamos como implementar el algoritmo anterior:
program Linear_Congruental_Method
implicit none
integer j
real A,I,C,M,num,den,cociente
A=4
I=1
C=1
M=9
do j=1, M
num=A*I+C
den=M
I=mod(num,den)
print*,j,I
end do
end program
Sin embargo, si A, C y M se escogen adecuadamente, entonces la secuencia es de
máxima longitud (es decir, M) y aleatoriamente distribuidos en el rango 0 a M-1.
Modifiquemos el programa anterior para testear nuestro generador de números
aleatorios representando Ij versus Ij+1:
program Linear_Congruental_Method
implicit none
integer j
real A, I, I1, I2, C, M, num, den, cociente
OPEN(1,FILE=’LCM.DAT’)
A=106
I=1
C=1283
M=6075
den=M
do j=1,1000
num=A*I+C
I=mod(num,den)
I1=I
num=A*I+C
I=mod(num,den)
I2=I
WRITE(1,*) I1,I2
end do
end program
obteniendo el siguiente resultado:
Se puede usar el compilador de MSDEV para generar números pseudo-aleatorios
usando como semilla (“seed”) el contador del reloj del ordenador.
El siguiente programa hace lo mismo que el anterior, pero con las subrutinas del
compilador:
program numeros_aleatorios
Implicit none
Integer:: count,nmax,i
Integer, dimension(1)::Seed
Real r,aux1,aux2
nmax=1000
CALL SYSTEM_CLOCK( Count )
Seed = Count
open(1,file='file_random2.dat')
do i=1,nmax
Call random_seed (Put=Seed)
Call Random_Number (r)
aux1=r
Call Random_Seed(Get=Seed)
Call random_seed (Put=Seed)
Call Random_Number (r)
aux2=r
Call Random_Seed(Get=Seed)
write(1,*)aux1,aux2
end do
end program
siendo el resultado el siguiente:
Ahora podemos discriminar el número aleatorio obtenido de la siguiente manera:
program numeros_aleatorios
Implicit none
Integer:: count,nmax,i
Integer, dimension(1)::Seed
Real r
real,dimension(10)::rr
rr=0
nmax=1000000
CALL SYSTEM_CLOCK( Count )
Seed = Count
!print*,seed
do i=1,nmax
Call random_seed (Put=Seed)
Call Random_Number (r)
if(r<0.1) then
rr(1)=rr(1)+1
else
if(r<0.2) then
rr(2)=rr(2)+1
else
if(r<0.3) then
rr(3)=rr(3)+1
else
if(r<0.4) then
rr(4)=rr(4)+1
else
if(r<0.5) then
rr(5)=rr(5)+1
else
if(r<0.6) then
rr(6)=rr(6)+1
else
if(r<0.7) then
rr(7)=rr(7)+1
else
if(r<0.8) then
rr(8)=rr(8)+1
else
if(r<0.9) then
rr(9)=rr(9)+1
else
rr(10)=rr(10)+1
end if
end if
end if
end if
end if
end if
end if
end if
end if
!print*,seed,i,r
Call Random_Seed(Get=Seed)
!print*,seed,i,r
!pause
end do
open(1,file='random3.dat')
do i=1,10
write(1,*)i/10.,rr(i)
end do
!100 format(10(F10.3))
end program
Si representamos el resultado en el formato de columnas, vemos que la probabilidad de
que el número generado aleatoriamente esté en un intervalo determinado es la misma
para todos los intervalos.
El criterio usado en el programa anterior para ordenar los números generados según el
intervalo, se puede extender al paseo aleatorio (RANDOM WALK). Por ejemplo, para
la variable x:
……….
dx=0.01
CALL RANDOM_SEED(Put=seed)
CALL RANDOM_NUMBER(sx)
CALL RANDOM_SEED(Get=seed)
IF(sx<0.5) THEN
x(i)=x(i)-dx
ELSE
x(i)=x(i)+dx
END IF
CALL RANDOM_SEED(Put=seed)
CALL RANDOM_NUMBER(sy)
CALL RANDOM_SEED(Get=seed)
y otro tanto haríamos para la variable y.
Descargar