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

Напишите действительно включенный случайный метод для javascript

Объект MATH Javascript имеет случайный метод, возвращающийся из набора [0,1) 0 включительно, 1 эксклюзивный. Есть ли способ вернуть действительно случайный метод, который включает в себя 1.

например.

var rand = MATH.random()*2;

if(rand > 1)
{
   rand = MATH.floor(rand);
}

return rand; 

Хотя это всегда возвращает число из набора [0,1], оно не является действительно случайным.

4b9b3361

Ответ 1

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

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

Ответ 2

Это вернет [0,1] включительно:

if(MATH.random() == 0)
    return 1;
else
    return MATH.random();

Объяснение: Если первый вызов random() возвращает 0, верните 1. В противном случае вызовите случайным снова, что будет [0,1). Поэтому он будет возвращать [0,1] все включено.

Ответ 3

Функция Math.random возвращает случайное число от 0 до 1, где 0 включено, а 1 - исключение. Это означает, что единственный способ правильно распределить случайные числа в виде целых чисел в интервале - использовать исключительный верхний предел.

Чтобы указать инклюзивный верхний предел, вы просто добавляете его к нему, чтобы сделать его исключительным в расчете. Это будет правильно распределять случайные числа между 7 и 12, включительно:

var min = 7;
var max = 12;
var rnd = min + Math.floor(Math.random() * (max - min + 1));

Ответ 4

Вы хотите, чтобы он включал 1?

return 1 - Math.random();

Однако, я думаю, что это один из тех вопросов, который намекает на другие проблемы. Зачем вам нужно включить 1? Вероятно, это лучший способ сделать это.

Ответ 5

Приложение:

Взглянув на исходный код java.util.Random, включенный в дистрибутив Oracle JDK 7 ( "Авторское право (c) 1995, 2010, Oracle и/или его ветки. Все права защищены. ORACLE PROPRIETARY/CONFIDENTIAL. на условиях лицензии" ) показывает этот простой код:

class Random {

    public float nextFloat() {
        return next(24) / ((float)(1 << 24));
    }

    protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
            oldseed = seed.get();
            nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }
}

Таким образом, для nextFloat():

  • Возьмите "случайное целочисленное значение" между 0 и 2 ^ 24-1 (точнее, случайный 24-битный битпаттерн, интерпретируемый как целочисленное значение),
  • Преобразовать его в float (в Java "float" имеет обязательную 32-битную точку с плавающей запятой IEEE 724, которая может представлять до 2 ^ 24 без потери точности, и таким образом это будет значение между 0 и 1.6777215E7)
  • Затем разделим его на float-представление 2 ^ 24, снова просто представим без потери точности, как 1.6777216E7. 2 ^ 24 + 1 = 16777217 упадет до 1,6777216E7, когда будет вынуждено плавать. В коде это действительно должно быть константой. Эй, солнце, циклы не растут на деревьях.
  • Подразделение приводит к поплавке в [0.0.. 0.99999994] (правильный результат разделения будет около 0.999999940395355224609375), с, я думаю, все возможные значения с плавающей запятой IEEE 724 между "одинаково возможно".

См. также плавающая точка IEEE и Арифметика с плавающей запятой на JVM.

Комментарии Javadoc для `next():

/**
 * Generates the next pseudorandom number. Subclasses should
 * override this, as this is used by all other methods.
 *
 * <p>The general contract of {@code next} is that it returns an
 * {@code int} value and if the argument {@code bits} is between
 * {@code 1} and {@code 32} (inclusive), then that many low-order
 * bits of the returned value will be (approximately) independently
 * chosen bit values, each of which is (approximately) equally
 * likely to be {@code 0} or {@code 1}. The method {@code next} is
 * implemented by class {@code Random} by atomically updating the seed to
 *  <pre>{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}</pre>
 * and returning
 *  <pre>{@code (int)(seed >>> (48 - bits))}.</pre>
 *
 * This is a linear congruential pseudorandom number generator, as
 * defined by D. H. Lehmer and described by Donald E. Knuth in
 * <i>The Art of Computer Programming,</i> Volume 3:
 * <i>Seminumerical Algorithms</i>, section 3.2.1.
 *
 * @param  bits random bits
 * @return the next pseudorandom value from this random number
 *         generator sequence
 * @since  1.1
 */

Комментарии Javadoc для nextFloat():

/**
 * Returns the next pseudorandom, uniformly distributed {@code float}
 * value between {@code 0.0} and {@code 1.0} from this random
 * number generator sequence.
 *
 * <p>The general contract of {@code nextFloat} is that one
 * {@code float} value, chosen (approximately) uniformly from the
 * range {@code 0.0f} (inclusive) to {@code 1.0f} (exclusive), is
 * pseudorandomly generated and returned. All 2<font
 * size="-1"><sup>24</sup></font> possible {@code float} values
 * of the form <i>m&nbsp;x&nbsp</i>2<font
 * size="-1"><sup>-24</sup></font>, where <i>m</i> is a positive
 * integer less than 2<font size="-1"><sup>24</sup> </font>, are
 * produced with (approximately) equal probability.
 *
 * <p>The method {@code nextFloat} is implemented by class {@code Random}
 * as if by:
 *  <pre> {@code
 * public float nextFloat() {
 *   return next(24) / ((float)(1 << 24));
 * }}</pre>
 *
 * <p>The hedge "approximately" is used in the foregoing description only
 * because the next method is only approximately an unbiased source of
 * independently chosen bits. If it were a perfect source of randomly
 * chosen bits, then the algorithm shown would choose {@code float}
 * values from the stated range with perfect uniformity.<p>
 * [In early versions of Java, the result was incorrectly calculated as:
 *  <pre> {@code
 *   return next(30) / ((float)(1 << 30));}</pre>
 * This might seem to be equivalent, if not better, but in fact it
 * introduced a slight nonuniformity because of the bias in the rounding
 * of floating-point numbers: it was slightly more likely that the
 * low-order bit of the significand would be 0 than that it would be 1.]
 *
 * @return the next pseudorandom, uniformly distributed {@code float}
 *         value between {@code 0.0} and {@code 1.0} from this
 *         random number generator sequence
 */

Ответ 6

Из того, что я вижу на консоли JavaScript в Chrome, Math.random() генерирует число от 0 до 0.9999999999999999. Принимая это во внимание, вы можете получить то, что хотите, добавив модификатор. Например, здесь функция, которая даст вам квази-случайное поплавок между 0 и 1, с 1 включительно:

function randFloat() {
  // Assume random() returns 0 up to 0.9999999999999999
  return Math.random()*(1+2.5e-16);
}

Вы можете попробовать это в консоли, введя 0.9999999999999999*(1+2.5e-16) - он вернет ровно 1. Вы можете взять это дальше и вернуть с помощью этой функции float от 0 до 1024 (включительно):

function randFloat(nMax) {
  // Assume random() returns 0 up to 0.9999999999999999
  // nMax should be a float in the range 1-1024
  var nMod;
  if (nMax<4) nMod = 2.5e-16;
  else if (nMax<16) nMod = 1e-15;
  else if (nMax<32) nMod = 3.5e-15;
  else if (nMax<128) nMod = 1e-14;
  else if (nMax<512) nMod = 3.5e-14;
  else if (nMax<1024) nMod = 1e-13;
  return Math.random()*(nMax+nMod);
}

Вероятно, существует более эффективный алгоритм.

Ответ 7

Поскольку этот вопрос задан снова, и я не читал этот подход, я добавлю еще один ответ.

ИМО, лучшее, что вы можете сделать, без лишних хлопот:

эксклюзив:

//simply ignore the 0
for(var rand=0; !rand;rand = Math.random());

//or simpler:
var rand = Math.random() || Math.random();
//because the probability for two consecutive `0` is pretty much non existant.

это даже не приводит к ошибке, так как мы просто исключили возможность возврата 0, каждое другое значение между 0 и 1 имеет ту же вероятность

включительно:

var rand = Math.random() * 2;
if(rand > 1) rand-=1;
//so the 0 shares it probability with the 1.

просто чтобы понять, насколько крошечная "ошибка":

  • вероятность a 0 или 1 равна
    1 / Math.pow(2, 54) или около 5.55e-17
  • вероятность любого другого значения между 0 и 1 равна
    1 / Math.pow(2, 53) или около 11.1e-17

и вся случайная функция будет:

function random(min, max, inclusive){
    var r = Math.random();
    if(inclusive)
        r = r>0.5? 2*r-1: 2*r;
    else 
        while(!r) r = Math.random();

    return r * (max - min) + min;
}

Изменить: Я не уверен, что я ошибаюсь, но не следует устанавливать вероятность включения в инклюзивный подход, если я добавлю еще один бит в нули и единицы и, следовательно, дублирую их вероятность:

var rand = Math.random() * 4;
rand = (rand % 1) || (rand & 1);