Подтвердить что ты не робот

Генерировать случайные числа в указанном диапазоне - различные случаи (int, float, inclusive, exclusive)

задана функция Math.random(), которая возвращает число между значениями [0,1) и min max, чтобы указать диапазон, как мы можем генерировать числа для следующих случаев:

Мы хотим целое число:

  • A: (min,max) ?
  • B: [min,max) return Math.floor(Math.random() * (max - min)) + min;
  • C: (min,max] ?
  • D: [min,max] return Math.floor(Math.random() * (max - min + 1)) + min;

Мы хотим float:

  • A: (min,max) ?
  • B: [min,max) return Math.random() * (max - min) + min;
  • C: (min,max] ?
  • D: [min,max] ?
4b9b3361

Ответ 1

Целые Ваша формула для B. правильная, все остальное получается тривиальными исправлениями +1 -1:

  • A. (min, max) = [min + 1, max), поэтому из B. получаем min + 1 + Math.floor(Math.random() * (max - min - 1))
  • В. min + Math.floor(Math.random() * (max - min))
  • С. Так как в интервале арифметики (min, max] = max - [0, max - min) можно было бы написать max - Math.floor(Math.random() * (max - min))
  • D. [min, max] = [min, max + 1), поэтому: min + Math.floor(Math.random() * (max + 1 - min))

Поплавки.. Как уже указывал V13, вопрос несколько некорректен: если мы рассматриваем отдельные точки как множества с нулем, то почти (в измеренном теоретическом смысле) нет разницы между четыре набора... Однако, если вы хотите гарантировать, что исключенные интервальные границы никогда (а не просто "почти никогда" ) не будут выбраны, и если вы предполагаете, что ошибок округления нет, вы можете сделать что-то вроде этого:

  • A: var middle = (min + max) / 2; var sign = Math.random() > 0.5 ? 1 : -1; return middle + sign * (max - min) / 2 * Math.random(); Это решение наносит меньшую массу на 0, но это должно быть незначительным для всех практических целей.

  • B: min + Math.random() * (max - min), да.

  • C: max - Math.random() * (max - min), симметричный выше.
  • D: Невозможно гарантировать, что мы когда-либо ударим верхнюю границу интервала, поэтому мы можем просто использовать min + Math.random() * (max - min).

Разница между A и D заключается в следующем: если мы попытались использовать формулу min + Math.random() * (max - min) в A, мы могли бы иногда получить a 0 (потому что диапазон возможных чисел на самом деле конечен). Однако никакая разумная статистика никогда не могла бы жаловаться, что верхняя граница не попадает в D.

Ответ 2

Integer:

  • A: return Math.floor(Math.random() * (max - min - 1)) + min + 1;
  • B: Правильно
  • C: Это то же самое, что и [min + 1, max + 1), поэтому: return Math.floor(Math.random() * (max - min)) + min + 1;
  • D: Правильно

Для поплавков вам нужно знать, какая у вас арифметика с плавающей запятой. Если вы не используете специальную библиотеку, равенство в float - это то, чего обычно не бывает, поэтому нет смысла иметь замкнутые диапазоны. Как таковая не должно быть никакой разницы между всеми четырьмя, и вы можете просто пойти с:

return Math.random() * (max-min) + min;

Чтобы вопрос имел смысл, вам нужно определить минимально допустимый диапазон для равенства (например, r=0.00000000000000001). После этого вы можете преобразовать ваши уравнения открытого диапазона (т.е. (min, max)) в [min+r, max-r].

Ответ 3

Начну с определения следующих двух вспомогательных функций, а затем используйте их для получения значений. Эти методы являются вашими определениями случаев B.

int nextInt(int min, int max) {
    return Math.floor(Math.random() * (max - min)) + min;
}

float nextFloat(float min, float max) {
    return Math.random() * (max - min) + min;
}

Затем для целых

  • A: return nextInt (min + 1, max);
  • B: return nextInt (min, max);
  • C: return nextInt (min + 1, max + 1);
  • D: return nextInt (min, max + 1);

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

A: В этом случае мы можем просто убедиться, что незаконное значение снова свернуто:

float f; 
do {
    f = nextFloat(min, max);
} while (f == min);
return f;

В:

return nextFloat(min, max);

C: Здесь мы просто переключаем конечную точку

float f = nextFloat(min, max);
if (f == min) {
    return max;
}
return f;

D: Это самый сложный сценарий для всех, но может быть достигнут следующим образом:

float f = nextFloat(min, max);
if (f == min) {
    return max;
}
return nextFloat(min, max);

Случаи A и D немного грязны в том смысле, что им может потребоваться генерация более одного случайного числа, что может быть проблемой в некоторых конкретных сценариях. Решение этого требует глубокого углубления спецификации спецификации с плавающей точкой для поиска альтернативных реализаций. Далее следует отметить, что в случае D способность к максимизации имеет очень немного более высокую проницаемость, чем любое другое число, если ссылочная функция полностью однородна (обычно нет), но обычно это только теоретический вопрос. (Если быть точным, если в пределах диапазона имеется n возможных значений, то возможностоимость максимального значения pmax = 1/(n-1) и прочность любого другого значения равна (1-pmax)/(n-1)).

Следует отметить небольшую проблему, которая должна быть учтена при точных реализациях с плавающей запятой A. Существует вероятность, что вызывающая функция вызовет ее со смежными плавающими точками. Это нелегко увидеть при помощи какой-либо фиктивной проверки параметров, поэтому, чтобы быть в безопасности, должно быть ограничение на то, сколько раз цикл может быть выполнен.