Ver Mensaje Individual
  #1 (permalink)  
Antiguo 14/12/2010, 16:39
Avatar de _cronos2
_cronos2
Colaborador
 
Fecha de Ingreso: junio-2010
Mensajes: 2.062
Antigüedad: 13 años, 10 meses
Puntos: 310
Función random mejorada

Bueno pues como explica el título del post, se me ocurrió hacer algunas ‘mejoras’ en la función random para tener un mayor control sobre los números aleatorios a la hora de trabajar con ellos. Permite introducir intervalos (de momento 2 como máximo, si alguien se ve con ganas y tiempo de mejorarla más para que se puedan meter todos los que hagan falta, adelante, y que por favor nos deje el código aquí (: ) abiertos y cerrados por izquierda y derecha, y hacer uniones y diferencias simétricas (intersecciones no porque con sólo dos intervalos no tiene mucho sentido). Además le he añadido un pequeño prototype al objeto para redondear o mostrar el número resultante, y unas funciones para no tener que poner "Math." cada vez. Por último, señalar que este código está dirigido a redondear el número (se ve bastante bien más abajo XD), así que si alguien usa este código esperando números para usarlos con decimales tendría que modificarlo un poco. Aquí os dejo el código:
Código Javascript:
Ver original
  1. function rnd(){
  2.  return Math.random();
  3. }
  4. function round(n){
  5.  return Math.round(n);
  6. }
  7. function power(n,x){
  8.  return Math.pow(n,x);
  9. }
  10. var minimo, alReves, union, partes, cual, rand, numeros, intervalos, num, i, j, resta, txt, intg, oper;
  11. minimo=(10).power(-16);
  12. alReves = {
  13.  '(' : ']',
  14.  ')' : '[',
  15.  '[' : ')',
  16.  ']' : '('
  17. };
  18. function random(str){
  19.  union = /u/i;
  20.  rand=rnd();
  21.  numeros=[];
  22.  if(/[\^u]/i.test(str)){ // varios intervalos
  23.   if(union.test(str)){ // unión de intervalos
  24.    partes=str.split(union); // separamos por el 'operador'
  25.    cual = rand>=(1-minimo)/partes.length?1:0; // decidimos en qué intervalo estará nuestro número
  26.    numeros=partes[cual].match(/\d+/g); // cogemos los números que haya en ese intervalo
  27.    resta=numeros[1]-numeros[0]; // restamos el menor al mayor
  28.    //alert('rand:'+rand+'\ncual:'+cual+'\nbool:'+bool+'\npartes:'+partes.join()+'\nnumeros:'+numeros.join()+'\nresta:'+resta);  
  29.    rand*=resta; // multiplicamos por la diferencia
  30.    rand+=parseFloat(numeros[0]); // sumamos el menor
  31.    //alert(rand);
  32.    if(rnd()>=(1-minimo)/partes.length) rand+=(cual?-1:1)*resta/2; // para que puedan darse todos los números
  33.    if(partes[cual].charAt(0)=='('&&round(rand)==numeros[0]) rand+=0.5; // si es abierto por la izquierda, evitamos que se redondee "mal"
  34.    if(partes[cual].lastCharAt(0)==')'&&round(rand)==numeros[1]) rand-=0.5; // si es abierto por la derecha, evitamos que se redondee "mal"
  35.    //alert(rand);
  36.   }else{
  37.    if(/\^/.test(str)){ // diferencia simétrica de conjuntos
  38.     var txt='', intg=str.match(/\d+/g), oper=str.match(/[\[\]()]/g); // [ ó ] ó ( ó )
  39.     txt+=oper[0]+intg[0]+','+intg[2]+alReves[oper[2]]+'U'+alReves[oper[3]]+intg[3]+','+intg[1]+oper[1];
  40.     // colocamos los elementos de los arrays de los match() según convenga
  41.     return new random(txt); // devolvemos un new random que cambiará la diferencia simétrica (^) por unión (U)
  42.    }
  43.   }
  44.  }else{ // sólo un intervalo
  45.   partes=str.split(','); // separamos el intervalo por la coma
  46.   numeros=str.match(/\d+/g); // cogemos los números que haya en ese intervalo
  47.   resta=numeros[1]-numeros[0]; // restamos el menor al mayor
  48.   rand*=resta; // multiplicamos por la diferencia
  49.   rand+=numeros[0]; // sumamos el menor
  50.   if(partes[0].charAt(0)=='('&&round(rand)==numeros[0]) rand+=0.5; // si es abierto por la izquierda, evitamos que se redondee "mal"
  51.   if(partes[0].lastCharAt(0)==')'&&round(rand)==numeros[1]) rand-=0.5; // si es abierto por la derecha, evitamos que se redondee "mal"
  52.  }
  53.  this.rand = rand; // asignamos la variable a la propiedad rand del objeto
  54. };
  55. random.prototype = {
  56.  ceil : function(){
  57.   return Math.ceil(this.rand);
  58.  },
  59.  floor : function(){
  60.   return Math.floor(this.rand);
  61.  },
  62.  round : function(){
  63.   return round(this.rand);
  64.  },
  65.  show : function(){
  66.   alert(this.rand);
  67.  }
  68. };
Por cierto, si alguien ve algún error que me lo diga pero hice 2 ó 3 pruebas así:
Código Javascript:
Ver original
  1. var aleatorio = new random('[0,8]^[3,7]'), i=0;
  2. while((aleatorio.round()>=0&&aleatorio.round()<3)||(aleatorio.round()>7&&aleatorio.round()<=8)){
  3.  i++;
  4.  aleatorio = new random('[0,8]^[3,7]'); // número entre 0 y 8 (inclusive) pero no entre 3 y 7 (inclusive)
  5. }
Y así:
Código Javascript:
Ver original
  1. var aleatorio = new random('[0,3)u(7,8]'), i=0;
  2. while((aleatorio.round()>=0&&aleatorio.round()<3)||(aleatorio.round()>7&&aleatorio.round()<=8)){
  3.  i++;
  4.  aleatorio = new random('[0,3)u(7,8]'); // número entre 0 y 8 (inclusive) pero no entre 3 y 7 (inclusive)
  5. }
Y FF me dijo que si quería detener el script porque no respondía (no probé en IE ni Chrome), así que me imagino que no será un fallo muy gordo.
Saludos (:
__________________
" Getting older’s not been on my plans
but it’s never late, it’s never late enough for me to stay. "
Cigarettes - Russian Red