Почему мой генератор случайных чисел JS настолько неправильн, когда я даю ему одно отрицательное и одно положительное число? - PullRequest
2 голосов
/ 01 июля 2011

Так что я использую такой скрипт для генерации случайных int внутри диапазона

function randomInRange(start, end)
{
  if ((start >= 0) && (end >= 0))
  {
    return Math.round(Math.abs(start) + (Math.random() * (Math.abs(end) - Math.abs(start))));

  }
  else if ((start <= 0) && (end <= 0))
  {
    return 0 - (Math.round(Math.abs(start) + (Math.random() * (Math.abs(end) - Math.abs(start)))));
  }
  else
  {
    return Math.round(((start) + Math.random() * (end - start)));
  }

}

Вы можете увидеть это на работе здесь . для положительных диапазонов это правильно, для отрицательных - это правильно, но я получаю плохие и неправильные результаты для смешанных. Почему и как это исправить?

Я пытаюсь использовать формулу как Math.round(start + Math.random() * (end - start));

Ответы [ 4 ]

4 голосов
/ 01 июля 2011

Если вы используете Math.round, вы получите неравномерное распределение.

Если вы, например, запросите числа от 2 до 4, только случайные числа от 2,0 до 2,5 будут округлены до 2, и только цифры от 3,5 до 4,0 будут округлены до 4, а числа от 2,5 до 3,5 будет округлено до 3. Это означает, что 50% чисел будет 3, тогда как только 25% будет 2, а 25% будет 4.

Вместо этого используйте Math.floor, чтобы получить равномерное распределение случайных чисел.

Вам не нужно проверять знак start и end, выражение end - start + 1 будет размером диапазона со знаком, отличающимся в зависимости от того, с какой стороны start это.

function randomInRange(start, end) {
  if (start > end) start++; else end++;
  return Math.floor((start + Math.random() * (end - start)));
}

Демонстрация: jsfiddle.net / guaEp / 1 /

Исправление:

Выражение end - start + 1 не работает, если start> end. Выражение end - start работает, если верхняя граница является исключительной, то есть диапазон от -10 до 11 возвращает числа в диапазоне от -10 до 10. Я добавил код, чтобы функция приняла включающую верхнюю границу и преобразовала ее в исключительную.

Также:

Как указал Дэвин, вы передаете строки функций, которые заставят функцию объединять строки вместо выполнения арифметических операций.

Просто преобразуйте строки в числа, используя функцию parseInt:

val.innerHTML = randomInRange(parseInt($('fnt').value), parseInt($('lint').value));
2 голосов
/ 01 июля 2011

ОК, я обнаружил проблему, вы выполняете алгебру над строками (поскольку в вашем коде $('fnt').value - это значение поля ввода, которое является строкой), а не числа, поэтому такие вещи, как +, будут заканчиваться конкатенация строк и не добавление их числового содержимого. В вашем конкретном примере у вас есть:

Math.round(((start) + Math.random() * (end - start)))

Что оценивается в:

Math.round((('13') + Math.random() * ('-666' - '13'))) 

Что оценивает (например):

Math.round("13-339.44615370430984")

Поскольку '13' + '-339.44615370430984' будет объединен, и, наконец, вызов Math.round вернет NaN

Вы должны иметь:

function randomInRange(start, end) {
  start = Number(start); end = Number(end);
  return Math.round(start + Math.random() * (end - start));
}

Или измените значения, которые вы передаете в функцию, убедившись, что они числа.

2 голосов
/ 01 июля 2011

Просто

function randomInRange(start, end) {
    return Math.round(start + Math.random() * (end - start));
}

должно работать.

jsFiddle Demo


ОБНОВЛЕНИЕ: Как правильно заметил @Guffa, распределение не будет равномерным. Вы можете использовать это:

return Math.floor(start-- + Math.random() * (end - start));
2 голосов
/ 01 июля 2011

Мне лень найти ошибку в вашем коде, но вычисление можно сделать гораздо проще:

function randomInRange(start, end)
{
    //Extra variables to make it easier to understand
    var rangeBegin = Math.min(start,end);
    var rangeEnd = Math.max(start,end);
    var rangeSize = rangeEnd-rangeBegin+1;    

    var seed = Math.random();
    var result = Math.floor((seed*rangeSize)+rangeBegin);

    return result;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...