Proste pytanie, ale interesują mnie tutaj niuanse.
Generuję losowe wartości logiczne za pomocą następującej metody, którą sam wymyśliłem:
const rand = Boolean(Math.round(Math.random()));
Ilekroć się random()
pojawia, wydaje się, że zawsze istnieje pułapka - nie jest naprawdę przypadkowa, jest zagrożona przez coś lub w inny sposób itp. Więc chciałbym wiedzieć:
a) Czy powyższe jest najlepszym sposobem, aby to zrobić?
b) Czy za dużo myślę?
c) Czy nie myślę o rzeczach?
d) Czy istnieje lepszy / szybszy / elegancki sposób, o którym nie wiem?
(Również trochę zainteresowany, jeśli B i C wykluczają się wzajemnie).
Aktualizacja
Jeśli to robi różnicę, używam tego do ruchu postaci AI.
const rand = Math.random() < 0.5
jest równoważne i prostsze.math.random
powinno być dużo. Po prostu użyj milisekund dla nasion.Boolean(+Date.now()%2)
Odpowiedzi:
Technicznie rzecz biorąc, kod wygląda dobrze, ale jest trochę zbyt złożony. Można porównać
Math.random()
do0.5
bezpośrednio, jak zakresieMath.random()
Is[0, 1)
(to znaczy „w przedziale od 0 do 1, w tym 0, ale nie 1”). Możesz podzielić zakres na[0, 0.5)
i[0.5, 1)
.var random_boolean = Math.random() <= 0.5;
// Example console.log(Math.random() <= 0.1) // %10 probability of getting "true" console.log(Math.random() <= 0.4) // %40 probability of getting "true" console.log(Math.random() <= 0.5) // %50 probability of getting "true" console.log(Math.random() <= 0.8) // %80 probability of getting "true" console.log(Math.random() <= 0.9) // %90 probability of getting "true"
źródło
let
np.let randomBool = Math.random() >= 0.5;
<
zamiast>=
?Math.random() < 0.5
nie obejmuje 0,5 dla dolnej połowy i nie obejmuje 1 dla górnej połowy - więc nadal jest to dokładnie 50% szansy. Poza tym jest krótszy. Moim zdaniemMath.random() < 0.1
bardziej intuicyjne jest odczytanie jako „10% szansy na prawdę” niżMath.random() >= 0.9
. Myślę, że to jednak dość wybredne. Niezła odpowiedź.Jeśli Twój projekt ma
lodash
, możesz:_.sample([true, false])
Alternatywnie możesz użyć własnej funkcji przykładowej ( źródło ):
const sample = arr => arr[Math.floor(Math.random() * arr.length)];
źródło
Aby uzyskać bardziej bezpieczną kryptograficznie wartość, możesz użyć
crypto.getRandomValues
w nowoczesnych przeglądarkach.Próba:
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;
Zauważ, że
crypto
obiekt jest API DOM, więc nie jest dostępny w Node, ale istnieje podobny interfejs API dla Node .źródło
Math.random()
jest notorycznie nieprzypadkowy na wiele sposobów, świetna alternatywna sugestiaa[0] > 127
!Math.round(Math.random());
źródło
Będąc pod dużym wrażeniem odpowiedzi Kelvina, chciałbym zaproponować dość podobne, ale nieco ulepszone rozwiązanie.
var randomBoolean = Math.random() < 0.5;
To rozwiązanie jest nieco bardziej oczywiste do odczytania, ponieważ liczba po prawej stronie
<
mówi o prawdopodobieństwie uzyskania,true
a nie otrzymaniafalse
, co jest bardziej naturalne do zrozumienia.<
Jest również krótszy o jeden symbol niż>=
;źródło
Potencjalnie szybsze rozwiązania ...
Podejście operatora bitowego, o którym właśnie pomyślałem
Math.random() + .5 >> 0
lub~~(Math.random() + .5)
. Oto test wydajności do samodzielnej oceny.let randomBoolean = Math.random() + .5 >> 0; //chance of true const randomBoolean = chance => Math.random() + chance >> 0; //chance of true
Operatory bitowe są w tym przypadku zasadniczo takie same jak użycie
Math.trunc()
lubMath.floor()
, dlatego też jest to możliweMath.trunc(Math.random() + .5)
.let randomBoolean = Math.trunc(Math.random() + .5); const randomBoolean = chance => Math.trunc(Math.random() + chance);
Inne, bardziej powszechne rozwiązania
Bardziej powszechnym sposobem uzyskania losowych wartości boolowskich jest prawdopodobnie podejście porównawcze, takie jak
Math.random() >= .5
z odpowiedzi Kelvina lubMath.random() < .5;
z odpowiedzi Arthura Khazbsa , które w rzeczywistości wyświetlają wartość prawda i fałsz, a nie 1 i 0.let randomBoolean = Math.random() >= .5; //chance of false const randomBoolean = chance => Math.random() >= chance; //chance of false let randomBoolean = Math.random() < .5; //chance of true const randomBoolean = chance => Math.random() < chance; //chance of true
Jedynym powodem do zastosowania tego
Math.round(Math.random())
podejścia jest prostota i lenistwo.źródło
(.49999999999999997 >= .5) != (.49999999999999997+ .5 >> 0)
A co z tym?
return Math.round((Math.random() * 1) + 0) === 0;
źródło
Odpowiedź Alexandra O'Mary
po prostu dodając fragment kodu węzła
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);
źródło