JS генерирует случайное логическое значение

136

Простой вопрос, но меня здесь интересуют нюансы.

Я генерирую случайные логические значения, используя следующий метод, который придумал сам:

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

random()Кажется, что всякий раз, когда он появляется, всегда есть ловушка - это не совсем случайность, что-то скомпрометировано и т. Д. Итак, я хотел бы знать:

а) Это лучший способ сделать это?

б) Я слишком много думаю о вещах?

в) Я что-то недооцениваю?

г) Есть ли способ лучше / быстрее / элегантнее, о котором я не знаю?

(Также несколько интересно, являются ли B и C взаимоисключающими.)

Обновить

Если это имеет значение, я использую это для передвижения персонажа AI.

Бен
источник
26
const rand = Math.random() < 0.5эквивалентно и проще.
Hamms
3
Вы можете добиться только псевдослучайности , а не истинной случайности.
Oriol
На самом деле нет ничего случайного, цель - максимально приблизиться к случайному.
Адам Бьюкенен Смит,
И если у вас есть шанс 50/50, math.randomдолжно быть много. Просто используйте миллисекунды для своего семени.
Адам Бьюкенен Смит,
Я думаю, это довольно случайный раз, когда кто-то посещает веб-сайт: D, так что у меня возникла эта идея ...Boolean(+Date.now()%2)
Роко С. Бульян

Ответы:

342

Технически код выглядит неплохо, но слишком сложно. Вы можете сравнить Math.random()с 0.5непосредственно, как диапазон Math.random()IS [0, 1)(это означает , что «в диапазоне от 0 до 1 , включая 0, но не 1»). Вы можете разделить диапазон на [0, 0.5)и [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
Мне нравится одно решение, так как оно позволяет вам настроить вероятность истинного / ложного
Эванион
если вы измените число 0,5 на 0,9, например, увеличит ли это вероятность ложного и как?
Агент Зебра
если изменить его с 0,5 на 0,9. Тогда вероятность, вероятно, изменится. Я думаю, вы можете попробовать это с большим количеством случайных циклов, например, 10000 итераций.
Кельвин
Для современного JavaScript вы должны использовать letielet randomBool = Math.random() >= 0.5;
Крис Хэлкроу,
Почему бы не использовать просто <вместо >=? Math.random() < 0.5не включает 0,5 для низкой половины и не включает 1 для высокой половины, так что это все равно точно 50% шанс. Плюс короче. И, на мой взгляд, Math.random() < 0.1более интуитивно понятнее читать «10% -й шанс истины», чем Math.random() >= 0.9. Я думаю, это довольно разборчиво. Хороший ответ.
Аарон Плохарчик,
27

Если у вас есть проект, lodashвы можете:

_.sample([true, false])
hthserhs
источник
13

Для более криптографически безопасного значения вы можете использовать crypto.getRandomValues в современных браузерах.

Образец:

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;

Обратите внимание, что cryptoобъект представляет собой DOM API, поэтому он недоступен в Node, но есть аналогичный API для Node .

Александр О'Мара
источник
4
Math.random()общеизвестно неслучайно во многих отношениях, отличное альтернативное предложение
Чарльз Харрис
3
Я просто собираюсь добавить здесь небольшую поправку, поскольку после 50 000 000 прогонов я обнаружил, что в среднем генерируется на 0,78% или около того больше нулей: return a [0] <= 127; (Остальное 127 никогда не включается)
Амунд Мидтског
2
@AmundMidtskog Хороший звонок. Надо было набрать:a[0] > 127
Александр О'Мара
1
Кстати, обычно вы можете захотеть сгенерировать гораздо большее количество выборок, чем просто 255. Скорее, чтобы уменьшить шум в данных, что-то вроде 100 000 - или даже десятков миллионов, как предлагается в другом комментарии, если вы хотите видеть ошибки размером всего 0,78%.
каркать
8
!Math.round(Math.random());

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

user12066722
источник
6
Пожалуйста, отформатируйте это более полезно ( stackoverflow.com/editing-help ) и добавьте некоторые пояснения. Ответы только на код не очень ценятся. Добавление объяснения поможет бороться с неправильным представлением о том, что StackOverflow - это бесплатный сервис для написания кода.
Юннош
5

Впечатленный ответом Кельвина, я хотел бы предложить довольно похожее, но немного улучшенное решение.

var randomBoolean = Math.random() < 0.5;

Это решение немного более очевидно для чтения, потому что число в правой части <говорит вам о вероятности получить, trueа не получить false, что более естественно для понимания. Также <на один символ короче >=;

Артур Хазбс
источник
1

Возможно более быстрое решение ...

Вы также можете рассмотреть подход побитового оператора, о котором я только что подумал Math.random() + .5 >> 0, не уверен, что он быстрее, но вот тест производительности, который вы можете проверить самостоятельно.

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

Наиболее распространенный способ получения случайной булевой является Math.random() >= .5от ответа Кельвина

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

Единственная причина использовать такой Math.round(Math.random())подход - простота и лень.

LeonNikolai
источник
Не уверен, стоит ли на это указывать, но(.49999999999999997 >= .5) != (.49999999999999997+ .5 >> 0)
Аарон Плохарчик
Ну да, но оба подхода неточны на этом уровне, поэтому я не думаю, что это имеет большое значение. (.49999999999999997 >=.5) == (.49999999999999991 +.5>>0)и это (.49999999999999998 >=.5) == (.49999999999999992 +.5>>0)правда. Также в побитовой версии мы определяем шанс получить истину, а в сравнительном примере мы определяем шанс получить ложь. Таким образом, .2 будет примерно равняться примерно 20% вероятности истинности при побитовой обработке или 20%
ложности
0

Как насчет этого?

return Math.round((Math.random() * 1) + 0) === 0;
Alex
источник
1
OP заявляет, что он уже использует аналогичные методы, нет необходимости публиковать это.
Jacob Gunther
-1

Ответ Александра О'Мара

просто добавляем фрагмент кода узла

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
источник