Sábado, 25 Agosto 2018 11:25

Dados cargados en $RANDOM

Ya hemos visto que $RANDOM%$limitesuperior no funciona.

Hemos visto que $RANDOM%1 para hacer tiradas "a cara o cruz" no funciona.

Y del mismo modo que deberemos sospechar (y no apostar) si vemos que un trilero siempre saca el mismo resultado lanzando una moneda, cuando lanza un dado puede que haga también trampa. Los dados se pueden cargar y hacer que un lado pese más, por lo que hay más posibilidades de que ese lado sea el que se apoye en la mesa y, por lo tanto, sea el lado apostado el que quede arriba. Pasa lo mismo con $RANDOM:

#!/bin/bash

let nocoincide=0

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -lt 10 ]
       then
            echo $numero >> coincidencias.txt
       fi
    
    done
done

for i in $(seq 0 9)
do
    echo "Veces que se repite "$i
    fgrep -o $i coincidencias.txt | wc -l
done

 

El resultado que me ha dado es (cada vez que lo probemos saldŕa algo distinto, ya que son números aleatorios):

Veces que se repite 0
7559
Veces que se repite 1
6668
Veces que se repite 2
5941
Veces que se repite 3
5730
Veces que se repite 4
5387
Veces que se repite 5
5219
Veces que se repite 6
5053
Veces que se repite 7
4810
Veces que se repite 8
4769
Veces que se repite 9
4638

 

Cuanto más pequeño es el número, más veces se repite. Curioso caso de "aleatoriedad". ¿No os resulta sospechoso? A mi, sí. Por lo que voy a compararlo con otros números. Y antes, voy a borrar coincidencias.txt para evitar viciar resultados:

rm coincidencias.txt

Y ahora, el script:

#!/bin/bash

let nocoincide=0

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -lt 10 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 100 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 500 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 750 ]
       then
            echo $numero >> coincidencias.txt
       elif [ $numero -eq 999 ]
       then
            echo $numero >> coincidencias.txt
       fi
    
    done
done

for i in $(seq 0 9)
do
    echo "Veces que se repite "$i":"
    fgrep -o $i coincidencias.txt | wc -l
done

echo "Datos de control"
for i in 100 500 750 999
do
    echo "Veces que se repite "$i":"
    fgrep -o $i coincidencias.txt | wc -l
done

Y el resultado:

Veces que se repite 0:
13717
Veces que se repite 1:
8694
Veces que se repite 2:
5986
Veces que se repite 3:
5651
Veces que se repite 4:
5389
Veces que se repite 5:
6259
Veces que se repite 6:
5029
Veces que se repite 7:
5339
Veces que se repite 8:
4796
Veces que se repite 9:
4701
Datos de control
Veces que se repite 100:
2296
Veces que se repite 500:
687
Veces que se repite 750:
277
Veces que se repite 999:
0

 

Ummmm... Como digo, algo que es aleatorio puede cambiar el resultado. Pero si siempre que ejecutamos el script nos da el mismo patrón, que es que cuanto más pequeño sea el número, más veces sale, es que esa aleatoriedad está tan viciada con los dados cargados de un trilero. Y es que $numero en $RANDOM%$numero no indica el límite superior sino el divisor de un dividendo aleatorio en una instrucción en la que le pedimos que nos indique el resto.

Ni más, ni menos.

Publicado en Programación
Sábado, 25 Agosto 2018 10:57

Más sobre la aleatoriedad de $RANDOM

En otro artículo ya comenté que para hacer una especie de "cara o cruz" en el que de forma aleatoria nos muestre 0 o 1, $RANDOM%1 no funciona, ya que siempre da 0. En un comentario me decían que dividir una cantidad entre 1 no da decimales. Es cierto, nunca podrá haber rendondeo a la alza porque nunca podrá haber redondeo y, por lo tanto, nunca podrá salir la cantidad indicada como límite superior del rango.

Voy a hacer un script en el que saquemos muchos números aleatorios. Por ejemplo, que mil veces haga una tirada aleatoria con resultados del 0 al 1.000. 

#!/bin/bash

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -eq $x ]
       then
            echo $x
       fi
    done
done

Al ejecutarlo no sale nada. Y repito, y repito, y repito la ejecución del script. Siempre sin ningún resultado. ¿Me habré equivocado? Voy a acumular las veces que el resultado no coincide con el límite superior:

#!/bin/bash

let nocoincide=0

for i in $(seq 1 1000)
do
    for x in $(seq 1 1000)
    do
       let numero=$((RANDOM%$x))
       if [ $numero -eq $x ]
       then
            echo $x
       else
            let nocoincide++
       fi
    
    done
done

echo "Han salido "$nocoincide" coincidencias con el límite superior"

Ahora el resultado siempre es el mismo:

Han salido 1000000 coincidencias con el límite superior

Pues igual no he sido yo el que me he equivocado. Aunque es cierto que al ser aleatorio puede que ese número no salga. Pero si varias veces repito un millón de tiradas y nunca coincide, algo raro pasa. Quizá lo raro es que quien afirma que para sacar un número aleatorio entre 0 y $x se puede conseguir con let numero=$((RANDOM%$x)) se equivoca... o que nunca se ha parado a comprobarlo.

Publicado en Programación

Si queremos un número aleatorio en Bash, tenemos la función de Bash RANDOM. Es una función del intérprete de comandos, por lo que no lo podemos ejecutar como comando, sino que si queremos desde la línea de comandos un número aleatorio, deberemos escribir:

echo $RANDOM

Esto nos dará un número aleatorio entre 0 y 32.768 (2 elevado a 15).

Pero, ¿qué pasa si queremos delimitar el rango en el que queremos el número aleatorio?

Podemos dividirlo por el límite superior y, al devolver el módulo, siempre será, como máximo, el número indicado menos uno. En muchos artículos y tutoriales  que dicen que el número que indicamos después del símbolo de porcentaje es el límite superior, pero esto no es así.

Veamos un caso extremo:

#!/bin/bash

contador=0
for i in $(seq 1 100000)
do
    let numero=$((RANDOM%1))
    if [ $numero -eq 1 ]
    then
        let contador=$contador+1
    fi
done
echo $contador

 

Le digo que haga un bucle cien mil veces y que calcule un número aleatorio entre el 0 y el 1. Que cuente cuantas veces sale 1 y muestre el número de veces que ha salido 1.

El resultado siempre es 0.

Así pues, cuando queráis un número aleatorio con un rango, sumadle uno al rango superior que le indiquéis a $RANDOM.

Publicado en Programación

¡Atención! Este sitio usa cookies y tecnologías similares.

Si no cambia la configuración de su navegador, usted acepta su uso. Saber más

Acepto

Vea nuestra política de cookies y enlaces de interés aquí