JS gera booleano aleatório

134

Pergunta simples, mas estou interessado nas nuances aqui.

Estou gerando booleanos aleatórios usando o método a seguir:

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

Sempre que random()aparece, parece que sempre há uma armadilha - não é verdadeiramente aleatória, é comprometida por uma coisa ou outra, etc. Então, eu gostaria de saber:

a) A maneira acima é a melhor prática para fazer isso?

b) Estou pensando demais nas coisas?

c) Estou subestimando as coisas?

d) Existe uma maneira melhor / mais rápida / elegante de que eu não conheço?

(Também um pouco interessado se B e C são mutuamente exclusivos.)

Atualizar

Se faz alguma diferença, estou usando isso para o movimento de um personagem de IA.

Ben
fonte
25
const rand = Math.random() < 0.5é equivalente e mais simples.
Hamms
3
Você só pode alcançar pseudo- aleatoriedade, não verdadeiramente aleatoriedade.
Oriol
Nada é realmente aleatório, o objetivo é chegar o mais próximo possível do acaso.
Adam Buchanan Smith
E se você tem uma chance de 50/50, math.randomdeve ser suficiente. Basta usar milissegundos para sua semente.
Adam Buchanan Smith
Eu acho que é bastante aleatória o tempo uma visita um site: D então eu tive esta idéia ...Boolean(+Date.now()%2)
Roko C. Buljan

Respostas:

337

Tecnicamente, o código parece bom, mas um pouco complexo demais. Você pode comparar Math.random()a 0.5diretamente, como a gama de Math.random()é [0, 1)(o que significa 'no intervalo de 0 a 1, incluindo 0, mas não 1'). Você pode dividir o intervalo em [0, 0.5)e [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"

Kelvin
fonte
3
I como este solução, pois permite que você ajustar a probabilidade de verdadeiro / falso
Evanion
se você alterar o número de 0,5 para 0,9, por exemplo, isso aumenta a probabilidade de falso e como?
Agent Zebra
se você mudar de 0,5 para 0,9. Então, é provável que a probabilidade seja alterada. Eu acho que você pode experimentá-lo com um grande número de loop aleatório, como 10000 iterações.
Kelvin
Para JavaScript moderno, você deve usar letielet randomBool = Math.random() >= 0.5;
Chris Halcrow
27

Se o seu projeto tiver lodash, você poderá:

_.sample([true, false])
hthserhs
fonte
13

Para um valor mais criptograficamente seguro, você pode usar crypto.getRandomValuesem navegadores modernos.

Amostra:

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;

Observe que o cryptoobjeto é uma API DOM, portanto não está disponível no Node, mas existe uma API semelhante para o Node .

Alexander O'Mara
fonte
4
Math.random()é notoriamente não-aleatória, em muitos aspectos, ótima sugestão alternativa
Charles Harris
3
Vou apenas adicionar uma pequena correção aqui, como descobri após 50 000 000 execuções que gerou em média 0,78% ou mais mais zeros: retorne um [0] <= 127; (Else 127 não está incluído)
Amund Midtskog
2
@AmundMidtskog Good call. Eu deveria ter digitado:a[0] > 127
Alexander O'Mara
1
A propósito, você pode geralmente gerar um número muito maior de amostras do que apenas 255. Em vez disso, para reduzir o ruído nos dados, algo como 100.000 - ou mesmo dezenas de milhões, conforme sugerido no outro comentário, se você deseja ver erros tão pequenos quanto 0,78%.
caw
8
!Math.round(Math.random());

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

user12066722
fonte
6
Formate isso de forma mais útil ( stackoverflow.com/editing-help ) e adicione algumas explicações. As respostas somente de código não são muito apreciadas. Adicionar uma explicação ajudaria a combater o equívoco de que o StackOverflow é um serviço gratuito de gravação de código.
Yunnosch 14/09/19
5

Impressionado muito com a resposta de Kelvin, gostaria de sugerir uma solução bastante semelhante, mas um pouco aprimorada.

var randomBoolean = Math.random() < 0.5;

Essa solução é um pouco mais óbvia de ler, porque o número à direita <indica a probabilidade de obter truee não de obter false, o que é mais natural de compreender. Também <é um símbolo menor que >=;

Arthur Khazbs
fonte
0

Que tal este?

return Math.round((Math.random() * 1) + 0) === 0;
Alex
fonte
1
OP afirma que ele já usa métodos semelhantes, não há necessidade de postar isso.
Jacob Gunther
-1

Resposta de Alexander O'Mara

apenas adicionando snippet de código do nó

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);

bFunc
fonte