PDA

Ver la versión completa : (java) Math.random()



CONTI
18/06/2003, 17:54
Hola! mirad taba aqui tudiando un poco y he llegado a la parte del random,y y bien se me plantea una cuestion,¿como puedo usar el random para que me salga un numero del 1 al 6?esto es por si queremos tirar un dado por ejemplo.Partimos de que el random solo ofrece numeros comprendidos entre el 0-1 y ademas es double.

La segunda pregunta seria como puedo cambiar a INT el random,es que no me compila por posible perdida de precision :_(

bueno gracias por responder :)

Juano
19/06/2003, 02:48
Pues para obtener un numero aleatorio del 1 al 6, basta con multiplicar el resultado del random por cualquier numero grande y luego obtener el modulo 6... lo que te dara un numero entre 0 y 5. Le sumas 1 y listo, tienes un numero entre 1 y 6 :wink:

Salu2.

CONTI
19/06/2003, 08:00
asias por responder,creo k te he entendido,pero no se si he implemetado bien lo que has dicho,de todas fomras me funciona :D haciendo esto,haber si te parece correcto:

import java.math.*;
class Ejercicio{
public static void main(String []args){
System.out.println((int)(Math.random()*6+1));
}
}

Juano
19/06/2003, 12:34
Creo que lo que has hecho no esta bien, tu funcion te va a devolver un numero entre 1 y 7, y ademas los resultados no son equiprobables; tienes muchas mas posibilidades de sacar un 1 o un 2 que un 5 o un 6, e incluso te puede llegar a salir un 7 alguna vez si el random te devuelve un valor igual a 1 :?

Lo que yo te decia era algo asi (Java no es mi fuerte, asi que te lo escribo en un pseudo-Java :wink:)



public static void main (String []args) {
n = (int)(Math.random() * 1000);
System.out.println ((n mod 6) + 1);
}


Salu2.

CONTI
19/06/2003, 15:24
asias ya esta =)

Bleach
20/06/2003, 12:32
No se como esta java pero he probado ese metodo en Delphi y he llegado a la conclusion que random de delphi es una distribución uniforme, y daba igual cualquiera de los dos metodos siempre daba una distribución uniforme.
Digo que no se como lo hara java pero no creo que varíe mucho el algoritmo, además me acuerdo de la carrera que me enseñaron un algoritmo para la generación de numeros pseudoaleatorios, (un ordenador solo puede generar estos), y la demostración de que producia una serie de numeros con distribucion uniforme.
No quiero polemizar pero me gustaría un demostración de que el algoritmo ((radom*5) + 1) esta tarado.

Un saludo.

Juano
21/06/2003, 03:42
No quiero polemizar pero me gustaría un demostración de que el algoritmo ((radom*5) + 1) esta tarado.
Vale, supongamos que random devuelve un numero pseudoaleatorio de 2 decimales entre entre 0.00 y 1.00, siguiendo una distribucion uniforme...

Esta claro que para obtener un 6 al tirar el dado, solo te vale obtener un 1.00 en el random, puesto que (1.00*5)+1=6, y para cualquier valor de random<1.00, el resultado sera distinto de 6... como por ejemplo (1.99*5)+1=5.95, cuyo valor entero truncado es 5. Luego la probabilidad de obtener un 6 al lanzar el dado es del 1% aproximadamente.

Si calculamos la probabilidad de sacar un 1 por ejemplo, se obtiene que para cualquier valor del random entre 0.00 y 0.19, el resultado da 1, ya que (0.19*5)+1=1.95, y su valor entero es 1. Por tanto, la probabilidad de obtener un 1 al lanzar el dado es aproximadamente del 20%, mucho mayor que la del 6...

Se ve claramente que con este algoritmo las probabilidades de cada numero van disminuyendo progresivamente del 1 al 6. En conclusion, ese dado esta trucado :mrgreen:

El algoritmo seria algo mejor si se redondeara el valor del float para obtener el resultado entero, en lugar de truncarlo a secas... pero igualmente tampoco es un algoritmo equiprobable valido, ya que de esta manera perjudica a los numeros 1 y 6... puedes comprobarlo tu mismo :wink:

Salu2.

PD: Lo mejor es usar el modulo de la division :roll:

Fújur
21/06/2003, 12:13
Según eso, haces el random, multiplicas por seis (obtienes un número entre 0 y 6) y redondeas siempre a la alza (no sé si en java existe ésta función, pero es un algoritmo muy simple de hacer). Eso ya debería ser equiprobable.

Juano
21/06/2003, 12:25
Según eso, haces el random, multiplicas por seis (obtienes un número entre 0 y 6) y redondeas siempre a la alza (no sé si en java existe ésta función, pero es un algoritmo muy simple de hacer). Eso ya debería ser equiprobable.
Si, pero con el detalle de que si te sale un 6.00 y lo redondeas a la alza te quedas con un 7! :shock: Para que funcione tienes que excluir el valor 1.00 del random :twisted:
Sigo pensando que lo mas sencillo es usar el modulo de la division y no complicarse la vida...


Salu2.

Fújur
21/06/2003, 12:36
Hombre, Juano, puedes verificar antes que el número que vas a redondear no sea un número entero.

De todas formas, si no es para una aplicación de cálculos estadísticos ( :wink: ), tienes razón en que tampoco es cuestión de comerse el tarro...

Lo más factible sería acoplar al ordenador un brazo-robot conectado por puerto serie, que tire un dado. Luego mediante una cámara y un programa de reconocimiento de formas lees el resultado del dado y lo aplicas al programa. No es rápido ni barato, pero lo que vas a fardar con tu ordenador-tahúr... :lol:

Un saludo.

Bleach
23/06/2003, 07:52
Siendo estrictos, 1000 no es divisible entre 6 y por lo tanto estas metiendo una tara, ya que hay mas probabilidad, de que salgan unos cuantos numeros, solo porque tiene un caso mas favorable.
Me convence este algoritmo si en vez de multiplicar por 1000 lo haces por 3000.

Un saludo.

Juano
23/06/2003, 10:56
Siendo estrictos, 1000 no es divisible entre 6 y por lo tanto estas metiendo una tara, ya que hay mas probabilidad, de que salgan unos cuantos numeros, solo porque tiene un caso mas favorable.
Me convence este algoritmo si en vez de multiplicar por 1000 lo haces por 3000.
:shock: :shock: :shock:
Es justo al contrario! Tienes que multiplicar el random obtenido por un numero NO divisible entre 6, ya que si lo multiplicas por un multiplo de 6 (como el 3000), entonces el modulo 6 del numero resultante (o sea, el resto de la division entera del numero entre 6) siempre te va a dar cero, y el random no te sirve de nada!!
Piensatelo bien... :roll:

Salu2.

Bleach
23/06/2003, 12:30
Es cierto que un multiplo de 6 da siempre modulo 0. fallo mio, lo correcto seria un numero que modulo 6 fuese 1. El caso es que 1000 tampoco vale, pero 1003 si.
Lo que pasa es que random en este caso da un espacion de 0 a 1000, o segun tu de 0 a 999 si cuentas los casos posibles tienes que para 1,2,3 y 4 hay 167 casos posibles de 1000, y para 4 y 5 tienes 166 (caso 0 a 999)
lo que nos dice que no es un distribucion equiprobable y no sirve. El mejor caso es cuando es multiplo de 6 pero nos estropea el algoritmo.
Con modulo 1, hay un caso mas en 0 y en 1 pero estos son los bordes del intervalo, 0 y 1003, y como tienen menos probabilidad de aparecer no supondra una tara importante.

Un saludo.

Juano
23/06/2003, 12:36
Lo que pasa es que random en este caso da un espacion de 0 a 1000, o segun tu de 0 a 999 si cuentas los casos posibles tienes que para 1,2,3 y 4 hay 167 casos posibles de 1000, y para 4 y 5 tienes 166 (caso 0 a 999) lo que nos dice que no es un distribucion equiprobable y no sirve.
Bueno... yo creo que un valor mas o menos en este caso no tiene importancia, teniendo en cuenta que el random tampoco devuelve un numero estrictamente aleatorio, podriamos despreciar ese pequeño error y considerar que el valor obtenido es pseudo-equiprobable :mrgreen:
De todas formas, tu observacion ha sido bastante buena :wink:

Salu2.

Bleach
24/06/2003, 07:08
De todas formas el algoritmo de random, da un distribucion estadisticamente equiprobable, y esta demostrado. Asi que cualquiera de los dos algoritmos es valido.

Ixidior
11/11/2007, 03:46
Estuve revisando que tipo de dato te soltaba realmente el Math.random() y te salen numeros entre e. 0 y el uno pero con una cantidad no definida de decimales, pero todos son 0.xx.......x. Entonces si lo multiplicamos por 10 tendriamos el primer numero de ese decimal. Por ejemplo, 0.245454787 *10 nos daria el numero 2. Ahora, tendriamos con este metodo 10 posibles numeros del 0 hasta el 9. Solo bastaria con poner una condicional para filtrar el rango de numeros que queremos. y si queremos un rango mas amplio solo bastaria con multiplicar el decimal por 100 o por 1000.

public int dado6(){

double x;
int entero;
while (true){

entero = math.random();

entero=(int)(x*10 )

/*a entero le damos el primer numero decimal que puede //estar entre el 0 y el 9*/

if(entero > 7 && entero >0 ){

return entero;
}
}
}

Diganme si seria esto algo equiprobable.

Saludos.

jgutierrez
11/11/2007, 11:22
Porque no simplificarlo a:



entero = math.random();

entero=(int)((x*6)+1);
return entero;
}

gothmog
11/11/2007, 11:53
Vale, supongamos que random devuelve un numero pseudoaleatorio de 2 decimales entre entre 0.00 y 1.00, siguiendo una distribucion uniforme...

Esta claro que para obtener un 6 al tirar el dado, solo te vale obtener un 1.00 en el random, puesto que (1.00*5)+1=6, y para cualquier valor de random<1.00, el resultado sera distinto de 6... como por ejemplo (1.99*5)+1=5.95, cuyo valor entero truncado es 5. Luego la probabilidad de obtener un 6 al lanzar el dado es del 1% aproximadamente.

Si calculamos la probabilidad de sacar un 1 por ejemplo, se obtiene que para cualquier valor del random entre 0.00 y 0.19, el resultado da 1, ya que (0.19*5)+1=1.95, y su valor entero es 1. Por tanto, la probabilidad de obtener un 1 al lanzar el dado es aproximadamente del 20%, mucho mayor que la del 6...

Se ve claramente que con este algoritmo las probabilidades de cada numero van disminuyendo progresivamente del 1 al 6. En conclusion, ese dado esta trucado :mrgreen:

El algoritmo seria algo mejor si se redondeara el valor del float para obtener el resultado entero, en lugar de truncarlo a secas... pero igualmente tampoco es un algoritmo equiprobable valido, ya que de esta manera perjudica a los numeros 1 y 6... puedes comprobarlo tu mismo :wink:

Salu2.

PD: Lo mejor es usar el modulo de la division :roll:

Creo que te lías demasiado, si entiendo la razón que das, porque lo normal con las funciones random es que dado un n como parámetro, te devuelvan valores entre 0 y n-1, precisamente para evitar la no equiprobabilidad.

Es decir, en este caso, la función random devolverá valores entre 0 y 0.9^, nunca 1.

De ahí lo de tener que hacer el +1 si quieres números entre 1 y 6. Si los quisieras entre 0 y 6, habría que multiplicar por 7.

Ixidior
16/11/2007, 23:58
Porque no simplificarlo a:



entero = math.random();

entero=(int)((x*6)+1);
return entero;
}

qu caso tendria usar ese algoritmo si no es realmente equiprobable. Si lo usaras en un programa estadistico tirarias todo al tacho pues las probabilidades de sacar 1 o 6 son realmente bajas a comparacion de los otros.

jgutierrez
17/11/2007, 14:22
qu caso tendria usar ese algoritmo si no es realmente equiprobable. Si lo usaras en un programa estadistico tirarias todo al tacho pues las probabilidades de sacar 1 o 6 son realmente bajas a comparacion de los otros.

Quien dice que no es equiprobable?
(math.random()*MAX)+MIN, da exactamente un número entre MIN y MAX, donde cada uno de ellos, tiene una probabilidad de 1/(MAX-MIN) de salir.