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.