JS génère un booléen aléatoire

135

Question simple, mais je suis intéressé par les nuances ici.

Je génère des booléens aléatoires en utilisant la méthode suivante que j'ai inventée moi-même:

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

Chaque fois que cela se random()présente, il semble qu'il y ait toujours un écueil - ce n'est pas vraiment aléatoire, c'est compromis par quelque chose ou autre, etc. Donc, j'aimerais savoir:

a) Est-ce que ce qui précède est la meilleure façon de procéder?

b) Est-ce que je réfléchis trop aux choses?

c) Est-ce que je réfléchis aux choses?

d) Y a-t-il un moyen meilleur / plus rapide / élégant que je ne connais pas?

(Aussi un peu intéressé si B et C sont mutuellement exclusifs.)

Mettre à jour

Si cela fait une différence, j'utilise ceci pour le mouvement d'un personnage IA.

Ben
la source
26
const rand = Math.random() < 0.5est équivalent et plus simple.
Hamms
3
Vous ne pouvez obtenir que du pseudo - aléatoire , pas vraiment du hasard.
Oriol
Rien n'est en fait aléatoire, le but est de se rapprocher le plus possible du hasard.
Adam Buchanan Smith
Et si vous avez une chance de 50/50, cela math.randomdevrait être suffisant. Utilisez simplement des millisecondes pour votre graine.
Adam Buchanan Smith
Je pense que c'est assez aléatoire le temps que l'on visite un site web: D alors j'ai eu cette idée ...Boolean(+Date.now()%2)
Roko C. Buljan

Réponses:

340

Techniquement, le code semble correct, mais juste un peu trop complexe. Vous pouvez comparer Math.random()à 0.5directement, comme la gamme de Math.random()est - [0, 1)(ce qui signifie « dans la plage de 0 à 1 , y compris 0, mais pas 1 »). Vous pouvez diviser la plage en [0, 0.5)et [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
la source
3
J'aime cette solution unique, car elle vous permet de modifier la probabilité de vrai / faux
Evanion
si vous changez le nombre de 0,5 à 0,9 par exemple, cela augmente-t-il la probabilité de faux, et comment?
Agent Zebra
si vous le changez de 0,5 à 0,9. Ensuite, la probabilité est susceptible d'être modifiée. Je pense que vous pouvez l'essayer avec un grand nombre de boucles aléatoires, comme 10000 itérations.
Kelvin
Pour JavaScript moderne, vous devez utiliser letielet randomBool = Math.random() >= 0.5;
Chris Halcrow
Pourquoi ne pas utiliser juste <au lieu de >=? Math.random() < 0.5est exclusif de 0,5 pour la moitié basse et exclusif de 1 pour la moitié haute - donc c'est toujours exactement une chance de 50%. De plus, c'est plus court. Et à mon avis, Math.random() < 0.1est plus intuitif à lire comme "10% de chance de vrai" que Math.random() >= 0.9. Je suppose que c'est assez difficile cependant. Bonne réponse.
Aaron Plocharczyk il y a
27

Si votre projet l'a fait, lodashvous pouvez:

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

Pour une valeur plus sécurisée cryptographiquement, vous pouvez utiliser crypto.getRandomValuesdans les navigateurs modernes.

Échantillon:

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;

Notez que l' cryptoobjet est une API DOM, il n'est donc pas disponible dans Node, mais il existe une API similaire pour Node .

Alexander O'Mara
la source
4
Math.random()est notoirement non aléatoire à bien des égards, excellente suggestion alternative
Charles Harris
3
Je vais juste ajouter une petite correction ici, comme je l'ai découvert après 50 000 000 d'exécutions qu'il a généré en moyenne 0,78% ou plus de zéros en plus: retourne un [0] <= 127; (Sinon 127 n'est jamais inclus)
Amund Midtskog
2
@AmundMidtskog Bon appel. J'aurais dû taper:a[0] > 127
Alexander O'Mara
1
À propos, vous voudrez peut-être généralement générer un nombre beaucoup plus grand d'échantillons que 255. Au lieu de cela, afin de réduire le bruit dans les données, quelque chose comme 100 000 - voire des dizaines de millions, comme suggéré dans l'autre commentaire, si vous voulez voir des erreurs aussi petites que 0,78%.
caw
8
!Math.round(Math.random());

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

user12066722
la source
6
Veuillez formater cela plus utilement ( stackoverflow.com/editing-help ) et ajouter quelques explications. Les réponses basées uniquement sur le code ne sont pas très appréciées. L'ajout d'une explication aiderait à combattre l'idée fausse selon laquelle StackOverflow est un service d'écriture de code gratuit.
Yunnosch le
5

Impressionné par la réponse de Kelvin, je voudrais suggérer une solution assez similaire mais légèrement améliorée.

var randomBoolean = Math.random() < 0.5;

Cette solution est un peu plus évidente à lire, car le nombre à droite de <vous indique la probabilité d'obtenir trueplutôt que d'obtenir false, ce qui est plus naturel à comprendre. <Un symbole est également plus court que >=;

Arthur Khazbs
la source
1

Solution potentiellement plus rapide ...

Vous pouvez également envisager l'approche d'opérateur Bitwise à laquelle je viens de penser Math.random() + .5 >> 0, je ne sais pas si c'est plus rapide, mais voici un test de performance à tester par vous-même.

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

Le moyen le plus courant d'obtenir un booléen aléatoire est la réponseMath.random() >= .5 de Kelvin

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

La seule raison d'utiliser cette Math.round(Math.random())approche est la simplicité et la paresse.

LéonNikolai
la source
Je ne sais pas si cela vaut la peine d'être souligné, mais(.49999999999999997 >= .5) != (.49999999999999997+ .5 >> 0)
Aaron Plocharczyk il y a
Eh bien oui, mais les deux approches sont inexactes à ce niveau, donc je ne pense pas que cela compte trop. (.49999999999999997 >=.5) == (.49999999999999991 +.5>>0)et (.49999999999999998 >=.5) == (.49999999999999992 +.5>>0)c'est à la fois vrai. Également dans la version bit à bit, nous définissons la chance d'obtenir vrai, tandis que l'exemple comparatif nous définissons la chance d'obtenir faux. Donc .2 équivaudrait à environ 20% de chance de vrai dans le bit, ou à 20% de faux dans l'approche comparative.
LeonNikolai il y a
0

Celui-ci, ça va?

return Math.round((Math.random() * 1) + 0) === 0;
Alex
la source
1
OP déclare qu'il utilise déjà des méthodes similaires, pas besoin de poster cela.
Jacob Gunther
-1

Réponse d' Alexandre O'Mara

ajouter simplement un extrait de code de nœud

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
la source