JS genera booleanos aleatorios


134

Pregunta simple, pero estoy interesado en los matices aquí.

Estoy generando booleanos aleatorios usando el siguiente método que se me ocurrió:

const rand = Boolean(Math.round(Math.random()));

Cada vez que random()aparece, parece que siempre hay una trampa: no es realmente aleatorio, está comprometido por algo u otro, etc. Entonces, me gustaría saber:

a) ¿Es lo anterior la mejor forma de hacerlo?

b) ¿Estoy pensando demasiado?

c) ¿Estoy sin pensar las cosas?

d) ¿Hay alguna forma mejor / más rápida / más elegante que no conozca?

(También algo interesado si B y C son mutuamente excluyentes).

Actualizar

Si hace la diferencia, estoy usando esto para el movimiento de un personaje AI.


25
const rand = Math.random() < 0.5Es equivalente y más simple.
Hamms

3
Solo puedes lograr pseudoaleatoriedad , no verdaderamente aleatoriedad.
Oriol

En realidad, nada es aleatorio, el objetivo es acercarse lo más posible al azar.
Adam Buchanan Smith

Y si tienes una probabilidad de 50/50, math.randomdebería ser suficiente. Solo usa milisegundos para tu semilla.
Adam Buchanan Smith

Creo que es bastante aleatorio el momento en que uno visita un sitio web: D, así que tuve esta idea ...Boolean(+Date.now()%2)
Roko C. Buljan

Respuestas:


338

Técnicamente, el código se ve bien, pero demasiado complejo. Puede comparar Math.random()a 0.5directamente, como la gama de Math.random()decir [0, 1)(esto significa 'en el rango de 0 a 1, incluyendo 0, pero no 1'). Puede dividir el rango en [0, 0.5)y [0.5, 1).

var random_boolean = Math.random() >= 0.5;

// Example
console.log(Math.random() >= 0.1) // %90 probability of get "true"
console.log(Math.random() >= 0.4) // %60 probability of get "true"
console.log(Math.random() >= 0.5) // %50 probability of get "true"
console.log(Math.random() >= 0.8) // %20 probability of get "true"
console.log(Math.random() >= 0.9) // %10 probability of get "true"


3
Me gusta esta solución, ya que le permite ajustar la probabilidad de verdadero / falso
Evanion

si cambia el número 0.5 a 0.9 por ejemplo, ¿esto aumenta la probabilidad de falso y cómo?
Agente Zebra

si lo cambia de 0.5 a 0.9. Entonces, es probable que se modifique la probabilidad. Creo que puedes probarlo con una gran cantidad de bucles aleatorios, como 10000 iteraciones.
Kelvin

Para JavaScript moderno, debería usar, por letejemplolet randomBool = Math.random() >= 0.5;
Chris Halcrow el

¿Por qué no usar solo en <lugar de >=? Math.random() < 0.5es exclusivo de 0.5 para la mitad baja y exclusivo de 1 para la mitad alta, por lo que sigue siendo exactamente un 50% de posibilidades. Además, es más corto. Y en mi opinión, Math.random() < 0.1es más intuitivo leerlo como "10% de posibilidades de verdad" que Math.random() >= 0.9. Aunque supongo que eso es ser bastante exigente. Buena respuesta.
Aaron Plocharczyk


13

Para obtener un valor más seguro criptográficamente, puede usar crypto.getRandomValues en navegadores modernos.

Muestra:

var randomBool = (function() {
  var a = new Uint8Array(1);
  return function() {
    crypto.getRandomValues(a);
    return a[0] > 127;
  };
})();

var trues = 0;
var falses = 0;
for (var i = 0; i < 255; i++) {
  if (randomBool()) {
    trues++;
  }
  else {
    falses++;
  }
}
document.body.innerText = 'true: ' + trues + ', false: ' + falses;

Tenga en cuenta que el cryptoobjeto es una API DOM, por lo que no está disponible en Node, pero hay una API similar para Node .


44
Math.random()es notoriamente poco aleatorio en muchos sentidos, gran sugerencia alternativa
Charles Harris

3
Voy a agregar una pequeña corrección aquí, como descubrí después de 50 000 000 ejecuciones que generó en promedio 0.78% más o menos más ceros: devuelve un [0] <= 127; (Else 127 nunca está incluido)
Amund Midtskog

2
@AmundMidtskog Buena llamada. Debería haber escrito:a[0] > 127
Alexander O'Mara

1
Por cierto, es posible que desee generar una cantidad mucho mayor de muestras que solo 255. Más bien, para reducir el ruido en los datos, algo así como 100,000, o incluso decenas de millones, como se sugiere en el otro comentario, si desea ver errores tan pequeños como 0.78%.
caw

8
!Math.round(Math.random());

­­­­­­­­­­­­­­


66
Formatee esto más útilmente ( stackoverflow.com/editing-help ) y agregue alguna explicación. Las respuestas de solo código no son muy apreciadas. Agregar una explicación ayudaría a combatir la idea errónea de que StackOverflow es un servicio gratuito de escritura de código.
Yunnosch

5

Impresionado mucho por la respuesta de Kelvin, me gustaría sugerir una solución bastante similar pero ligeramente mejorada.

var randomBoolean = Math.random() < 0.5;

Esta solución es un poco más obvia de leer, porque el número en el lado derecho de <le indica la probabilidad de obtener en truelugar de obtener false, lo cual es más natural de comprender. también< es un símbolo más corto que >=;


1

Solución potencialmente más rápida ...

También puede considerar el enfoque del operador Bitwise en el que acabo de pensar Math.random() + .5 >> 0, no estoy seguro de si es más rápido, pero aquí hay una prueba de rendimiento para probarlo usted mismo.

let randomBoolean = Math.random() + .5 >> 0;
const randomBoolean = chance => Math.random() + chance >> 0;

La forma más común de obtener booleanos aleatorios es Math.random() >= .5

let randomBoolean = Math.random() >= .5;       
const randomBoolean = chance => Math.random() >= chance;

La única razón para usar el Math.round(Math.random())enfoque es la simplicidad y la pereza.


No estoy seguro de si vale la pena señalar esto, pero(.49999999999999997 >= .5) != (.49999999999999997+ .5 >> 0)
Aaron Plocharczyk hace

0

¿Que tal este?

return Math.round((Math.random() * 1) + 0) === 0;

1
OP afirma que él ya usa métodos similares, no es necesario publicar esto.
Jacob Gunther

-1

Respuesta de Alexander O'Mara

simplemente agregando un fragmento de código de nodo

const crypto = require('crypto');
const randomBool = (function () {
    let a = new Uint8Array(1);
    return function () {
        crypto.randomFillSync(a);
        return a[0] > 127;
    };
})();

let trues = 0;
let falses = 0;
for (let i = 0; i < 100; i++) {
    if (randomBool()) {
        trues++;
    }
    else {
        falses++;
    }
}

console.log('true: ' + trues + ', false: ' + falses);

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.