JS genera un valore booleano casuale


134

Domanda semplice, ma sono interessato alle sfumature qui.

Sto generando booleani casuali utilizzando il seguente metodo che mi è venuto in mente:

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

Ogni volta che si random()presenta, sembra che ci sia sempre una trappola - non è veramente casuale, è compromesso da qualcosa o altro, ecc. Quindi, mi piacerebbe sapere:

a) Quanto sopra è il modo migliore per farlo?

b) sto pensando troppo alle cose?

c) Sto pensando male?

d) Esiste un modo migliore / più veloce / elegante che non conosco?

(Anche un po 'interessato se B e C si escludono a vicenda.)

Aggiornare

Se fa la differenza, lo sto usando per il movimento di un personaggio AI.


25
const rand = Math.random() < 0.5è equivalente e più semplice.
Hamms

3
Puoi ottenere solo pseudorandomualità , non veramente casualità.
Oriol,

Nulla è in realtà casuale, l'obiettivo è avvicinarsi il più possibile al casuale.
Adam Buchanan Smith,

E se hai una probabilità 50/50, math.randomdovrebbe essere abbondante. Usa i millisecondi per il tuo seme.
Adam Buchanan Smith,

Penso che sia abbastanza casuale quando si visita un sito Web: D, quindi ho avuto questa idea ...Boolean(+Date.now()%2)
Roko C. Buljan,

Risposte:


338

Tecnicamente, il codice sembra a posto, ma è un po 'troppo complesso. È possibile confrontare Math.random()a 0.5direttamente, come la gamma di Math.random()IS [0, 1)(questo significa 'nel range 0 a 1 tra cui 0, ma non 1'). È possibile dividere l'intervallo in [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"


3
Mi piace questa soluzione, in quanto ti consente di modificare la probabilità di vero / falso
Evanion

se si modifica il numero da 0,5 a 0,9 per esempio, ciò aumenta la probabilità di falso e come?
Agente Zebra

se lo cambi da 0,5 a 0,9. Quindi, è probabile che la probabilità sia cambiata. Penso che tu possa provarlo con un gran numero di loop casuali, come 10000 iterazioni.
Kelvin

Per JavaScript moderno dovresti usare letielet randomBool = Math.random() >= 0.5;
Chris Halcrow il

Perché non usare solo <invece di >=? Math.random() < 0.5è esclusivo di 0,5 per la metà bassa ed esclusivo di 1 per la metà alta, quindi è ancora esattamente una probabilità del 50%. Inoltre, è più corto. E secondo me, Math.random() < 0.1è più intuitivo leggere come "10% di probabilità di vero" di Math.random() >= 0.9. Immagino che sia piuttosto schizzinoso però. Bella risposta.
Aaron Plocharczyk


13

Per un valore più crittograficamente sicuro, è possibile utilizzare crypto.getRandomValuesnei browser moderni.

Campione:

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;

Si noti che l' cryptooggetto è un'API DOM, quindi non è disponibile in Nodo, ma esiste un'API simile per Nodo .


4
Math.random()è notoriamente non casuale in molti modi, ottimo suggerimento alternativo
Charles Harris

3
Aggiungerò solo una piccola correzione qui, come ho scoperto dopo 50.000.000 di esecuzioni che ha generato in media lo 0,78% o più di zero: return a [0] <= 127; (Else 127 non è mai incluso)
Amund Midtskog il

2
@AmundMidtskog Buona chiamata. Avrei dovuto digitare:a[0] > 127
Alexander O'Mara il

1
A proposito, di solito potresti voler generare un numero di campioni molto più grande di solo 255. Piuttosto, al fine di ridurre il rumore nei dati, qualcosa come 100.000 - o addirittura decine di milioni, come suggerito nell'altro commento, se vuoi vedere errori fino allo 0,78%.
Caw

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

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


6
Formatta questo in modo più utile ( stackoverflow.com/editing-help ) e aggiungi alcune spiegazioni. Le risposte di solo codice non sono molto apprezzate. L'aggiunta di una spiegazione aiuterebbe a combattere l'idea sbagliata che StackOverflow sia un servizio gratuito di scrittura di codice.
Yunnosch,

5

Impressionato molto dalla risposta di Kelvin, vorrei suggerire una soluzione abbastanza simile ma leggermente migliorata.

var randomBoolean = Math.random() < 0.5;

Questa soluzione è un po 'più ovvia da leggere, perché il numero sul lato destro <indica la probabilità di ottenere truepiuttosto che di ottenere false, il che è più naturale da comprendere. Inoltre <un simbolo è più corto di >=;


1

Soluzione potenzialmente più veloce ...

Puoi anche considerare l'approccio dell'operatore Bitwise a cui ho appena pensato Math.random() + .5 >> 0, non sono sicuro che sia più veloce, ma ecco un test delle prestazioni da testare da solo.

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

Il modo più comune per ottenere un booleano casuale è Math.random() >= .5

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

L'unica ragione per usare l' Math.round(Math.random())approccio è la semplicità e la pigrizia.


Non sono sicuro che valga la pena sottolineare, ma(.49999999999999997 >= .5) != (.49999999999999997+ .5 >> 0)
Aaron Plocharczyk

0

Che ne dici di questo?

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

1
OP afferma che utilizza già metodi simili, non è necessario pubblicarlo.
Jacob Gunther,

-1

Risposta di Alexander O'Mara

semplicemente aggiungendo lo snippet di codice 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);

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.