Logo Studenta

¿Cómo generan los lenguajes de programación números aleatorios? ¿Qué es lo que ocurre destras de escena?

💡 1 Respuesta

User badge image

Aprender y Estudiar

Los números aleatorios que produce una computadora no son en realidad aleatorios, sino pseudo-aleatorios. Esto significa que estadísticamente parecen ser aleatorios (su distribución está uniformemente balanceada, es decir, si fuera un dado, no estaría cargado), sin embargo, el algoritmo que los produce sigue una secuencia determinada, finita y repetible.

Los generadores de números aleatorios parten de un valor semilla. Esta semilla se manipula aritméticamente para producir un nuevo valor, el cual servirá a su vez como parte del estado que generará el siguiente valor en la secuencia.

El siguiente ejemplo viene de la libería std de C++ y corresponde a un generador muy simple, el std::minstd_rand0. Su fórmula es la siguiente

  1. x[n+1] = x[n] * 16807 % 2147483647 

Es decir, asumiendo que x[n] es la semilla actual, el siguiente número en la secuencia se obtendrá multiplicando ese valor por 16,807, luego se dividirá entre 2,147,483,647 y se utilizará el residuo de la división como el resultado (y futuro valor semilla en la siguiente generación de un número aleatorio). Este algoritmo en particular, genera todos los números enteros que hay en el rango numerico [1..2147483647], sin repeticiones y en un cierto orden, aparentemente aleatorio. Si se invoca el número suficiente de veces, la secuencia se reiniciará y producirá nuevamente los mismos números, en el mismo orden.

Este algoritmo es muy rápido, pero posee una correlación secuencial que pudiera no hacerlo apto en ciertos escenarios. Por ejemplo, si nuestra aplicación requiriera generar números aleatorios en el rango de [0..2147483647], no obtendríamos ningún número repetido hasta agotar la secuencia, lo cual claramente NO es un valor estadísticamente aleatorio. Sin embargo, en muchos escenarios se realiza una operación de mapeo para restringir el rango a un valor menor (por ejemplo el rango [1..6] para el caso de un dado convencional) y esa operación tiende a 'enmascarar' dicha correlación al introducir forzadamente repeticiones con una distribución más o menos uniforme (en general, a mayor rango deseado de valores, mayores serían las anomalías en la distribución).

Algoritmos mas complejos pueden mantener múltiples variables de estado para reducir la correlación secuencial, sin embargo casi todos parten de un único valor semilla que inicializa el estado del generador.

Como un ejemplo de un generador mas complejo, se puede consultar el código del generador de números aleatorios del .Net Framework en esta liga. Si se analiza el código, se verá que el estado del generador se almacena en un arreglo con 55 variables numéricas, manipulando un par de ellas de manera cíclica cada que se genera un número aleatorio (ver InternalSample()). Sin embargo, el estado de esas 55 variables se inicializa a partir de un único valor semilla de 32 bits (ver public Random(int Seed)). Al introducir esas 55 variables de estado, lo que estamos haciendo es incrementar sustancialmente el periódo de la secuencia, es decir, incrementar el número de elementos dentro de la secuencia antes de que ésta se reinicie, permitiendo repeticiones bien distribuidas sin necesidad de una operación de mapeo como en el caso del algoritmo mas simple descrito anteriormente.

Para aparentar un mayor grado de falsa "aleatoreidad", los lenguajes de programación normalmente inicializan el valor semilla del generador con un número relacionado con la fecha y hora del sistema, lo que hace que la secuencia tienda a iniciar en una posición diferente con cada ejecución del programa. Como un ejemplo de esto último, podemos ver en el generador de números aleatorios del .Net Framework, el siguiente constructor:

  1. public Random()  
  2. : this(Environment.TickCount) { 
  3. } 

El valor Environment.TickCount que se está usando como semilla corresponde a un valor en milisegundos que se actualiza cada que transcurren 15.6 milisegundos en una PC convencional. Eso le da una periodicidad de aproximadamente 49.7 días, antes de que se desborde y comience nuevamente en cero. La implicación de esta implementación, sería que si iniciamos dos instancias de la clase Random en tiempos muy próximos (antes de que el contador sea incrementado), ambas instancias del generador producirán exactamente la misma secuencia de números aleatorios ya que su semilla de inicialización será para ambas, el mismo valor de Ticks.

Verdaderos generadores aleatorios (True Random Number Generators)

Para aplicaciones que requieren números verdaderamente aleatorios, se pueden conseguir tarjetas PCI especializadas que los pueden generar mediante procesos físicos (por ejemplo micro-fluctuaciones térmicas en un sensor de alta resolución, o captura de ruido radioeléctrico atmosférico). También hay sitios como True Random Number Service (random.org) que ofrecen una API accesible por Internet para obtener numeros verdaderamente aleatorios.

0
Dislike0

✏️ Responder

FlechasNegritoItálicoSubrayadaTachadoCitaCódigoLista numeradaLista con viñetasSuscritoSobreDisminuir la sangríaAumentar la sangríaColor de fuenteColor de fondoAlineaciónLimpiarInsertar el linkImagenFórmula

Para escribir su respuesta aquí, Ingresar o Crear una cuenta

User badge image

Otros materiales