Победитель Javascript от случайных чисел с процентом [дубликат]

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null.

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

35
задан Daniel A. White 10 June 2015 в 23:08
поделиться

10 ответов

Отбраковка выборки (например, в вашем решении) - это первое, что приходит на ум, в результате чего вы создаете таблицу поиска с элементами, заполненными их распределением по весу, а затем выбираете случайное местоположение в таблице и вернуть его. В качестве варианта реализации я бы сделал функцию более высокого порядка, которая принимает спецификацию и возвращает функцию, которая возвращает значения, основанные на распределении в спецификации, таким образом вы избегаете создания таблицы для каждого вызова. Недостатком является то, что алгоритмическая производительность построения таблицы линейна по количеству элементов, и потенциально может быть много использования памяти для больших спецификаций (или те, у которых есть члены с очень малыми или точными весами, например {0: 0.99999, 1 : 0,00001}). Потенциал заключается в том, что выбор значения имеет постоянное время, что может быть желательно, если производительность критическая. В JavaScript:

function weightedRand(spec) {
  var i, j, table=[];
  for (i in spec) {
    // The constant 10 below should be computed based on the
    // weights in the spec for a correct and optimal table size.
    // E.g. the spec {0:0.999, 1:0.001} will break this impl.
    for (j=0; j<spec[i]*10; j++) {
      table.push(i);
    }
  }
  return function() {
    return table[Math.floor(Math.random() * table.length)];
  }
}
var rand012 = weightedRand({0:0.8, 1:0.1, 2:0.1});
rand012(); // random in distribution...

Другая стратегия состоит в том, чтобы выбрать случайное число в [0,1) и перебрать весовую спецификацию, суммируя веса, если случайное число меньше суммы, а затем возвращает связанное значение. Конечно, это предполагает, что веса суммируются до единицы. Это решение не имеет начальных затрат, но имеет среднюю алгоритмическую производительность, линейную по количеству записей в спецификации. Например, в JavaScript:

function weightedRand2(spec) {
  var i, sum=0, r=Math.random();
  for (i in spec) {
    sum += spec[i];
    if (r <= sum) return i;
  }
}
weightedRand2({0:0.8, 1:0.1, 2:0.1}); // random in distribution...
53
ответ дан maerics 19 August 2018 в 01:08
поделиться
  • 1
    Очень тщательный и полезный. Спасибо, что нашли время ответить на это. – Todd Sharp 8 December 2011 в 21:15
  • 2
    Обратите внимание, что вы можете сохранить массив, дающий кумулятивные суммы, т. Е. Сделать это один раз, а затем использовать бинарный поиск log n каждый раз, когда вы создаете число. Но это имеет смысл только для больших n. – dan-man 7 May 2016 в 14:03
  • 3
    Если я запускаю функцию с этими параметрами arr = {0: 0,1, 1: 0,7, 2: 0,9} 10000 раз, она дает мне этот результат: 0: 983, 1: 7011 и 2: 2006, что все неправильно, потому что 2 больше вероятности, чем 1, в то время как outout предлагает что-то другое. – Rüzgar 6 May 2017 в 10:47
  • 4
    @maerics Эй, просто быстрая проверка с вами, действительно ли сумма веса должна быть ровно 1? Я пробовал этот weightedRand ({0: 0.350, 1: 0.200, 2: 0.010, 3: 0.150, 4: 0.010, 5: 0.200, 6: 0.150}); но я понял, что число 4 часто встречается с очень большим числом – hyperfkcb 2 December 2017 в 10:26
  • 5
    @hyperfkcb да, сумма весов должна быть одной, и для этих весов вам нужно будет использовать постоянное значение 1000 вместо 10. – maerics 2 December 2017 в 16:30

Как насчет

int [] numbers = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2};

, тогда вы можете случайно выберите из чисел и 0 будет иметь вероятность 80%, 1 10% и 2 10%

5
ответ дан emory 19 August 2018 в 01:08
поделиться
  • 1
    Это работает, но нет необходимости выделять массив. Что делать, если вам приходится иметь дело с очень точной массой, например 4.68342%? Вам нужно выделить массив размером не менее 10000000. – Thomas Eding 8 December 2011 в 20:15

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

weights = {0.5,1,2}; // The weights
weights = N@weights/Total@weights // Normalize weights so that the list's sum is always 1.
min = 0; // First min value should be 0
max = weights[[1]]; // First max value should be the first element of the newly created weights list. Note that in Mathematica the first element has index of 1, not 0.
random = RandomReal[]; // Generate a random float from 0 to 1;
For[i = 1, i <= Length@weights, i++,
    If[random >= min && random < max,
        Print["Chosen index number: " <> ToString@i]
    ];
    min += weights[[i]];
    If[i == Length@weights,
        max = 1,
        max += weights[[i + 1]]
    ]
]

(Теперь я говорю с индексом первого элемента списка равен 0) . Идея заключается в том, что с нормализованным списком весов существует вероятность того, что вес [n] вернет index n , поэтому расстояния между min и max на шаге n должны быть весами [n] . Общее расстояние от минимального min (которое мы считаем равным 0) , а максимальное максимальное - суммой весов списка .

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

Вот код на C #, не требующий нормализации веса и удаление некоторого кода:

int WeightedRandom(List<float> weights) {
    float total = 0f;
    foreach (float weight in weights) {
        total += weight;
    }

    float max = weights [0],
    random = Random.Range(0f, total);

    for (int index = 0; index < weights.Count; index++) {
        if (random < max) {
            return index;
        } else if (index == weights.Count - 1) {
            return weights.Count-1;
        }
        max += weights[index+1];
    }
    return -1;
}
1
ответ дан Garmekain 19 August 2018 в 01:08
поделиться

Это более или менее универсальная версия того, что написал @trinithis, в Java: я делал это с помощью int, а не с плавающей точкой, чтобы избежать беспорядочных ошибок округления.

static class Weighting {

    int value;
    int weighting;

    public Weighting(int v, int w) {
        this.value = v;
        this.weighting = w;
    }

}

public static int weightedRandom(List<Weighting> weightingOptions) {

    //determine sum of all weightings
    int total = 0;
    for (Weighting w : weightingOptions) {
        total += w.weighting;
    }

    //select a random value between 0 and our total
    int random = new Random().nextInt(total);

    //loop thru our weightings until we arrive at the correct one
    int current = 0;
    for (Weighting w : weightingOptions) {
        current += w.weighting;
        if (random < current)
            return w.value;
    }

    //shouldn't happen.
    return -1;
}

public static void main(String[] args) {

    List<Weighting> weightings = new ArrayList<Weighting>();
    weightings.add(new Weighting(0, 8));
    weightings.add(new Weighting(1, 1));
    weightings.add(new Weighting(2, 1));

    for (int i = 0; i < 100; i++) {
        System.out.println(weightedRandom(weightings));
    }
}
10
ответ дан Greg Case 19 August 2018 в 01:08
поделиться

У меня есть slotmachine, и я использовал код ниже для генерации случайных чисел. В вероятностяхSlotMachine ключи являются выходными данными в slotmachine, а значения представляют вес.

const probabilitiesSlotMachine         = [{0 : 1000}, {1 : 100}, {2 : 50}, {3 : 30}, {4 : 20}, {5 : 10}, {6 : 5}, {7 : 4}, {8 : 2}, {9 : 1}]
var allSlotMachineResults              = []

probabilitiesSlotMachine.forEach(function(obj, index){
    for (var key in obj){
        for (var loop = 0; loop < obj[key]; loop ++){
            allSlotMachineResults.push(key)
        }
    }
});

Теперь, чтобы сгенерировать случайный вывод, я использую этот код:

const random = allSlotMachineResults[Math.floor(Math.random() * allSlotMachineResults.length)]
0
ответ дан J. Doe 19 August 2018 в 01:08
поделиться

здесь вход и отношения: 0 (80%), 1 (10%), 2 (10%)

позволяют вывести их, чтобы их было легко визуализировать.

                0                       1        2
-------------------------------------________+++++++++

позволяет суммировать общий вес и называть его TR для общего соотношения. поэтому в этом случае 100. позволяет случайным образом получить число из (0-TR) или (от 0 до 100 в этом случае). 100 - это ваш вес. Назовите это RN для случайного числа.

, так что теперь мы имеем TR как общий вес и RN как случайное число между 0 и TR.

, поэтому представьте себе, что мы выбрали случайный # из 0 до 100. Скажите 21. так что на самом деле 21%.

МЫ ДОЛЖНЫ ПРЕОБРАЗОВАТЬ / СЧИТАТЬ ЭТО К НАШИМ ВХОДНЫМ ЧИСЛАМ, НО КАК?

позволяет перебирать каждый вес (80, 10, 10) и сохраните сумму весов, которые мы уже посетили. момент, в течение которого мы перебираем веса, больше случайного числа RN (в этом случае 21), мы останавливаем цикл & amp; верните это положение элемента.

double sum = 0;
int position = -1;
for(double weight : weight){
position ++;
sum = sum + weight;
if(sum > 21) //(80 > 21) so break on first pass
break;
}
//position will be 0 so we return array[0]--> 0

позволяет сказать, что случайное число (от 0 до 100) равно 83. Давайте сделаем это снова:

double sum = 0;
int position = -1;
for(double weight : weight){
position ++;
sum = sum + weight;
if(sum > 83) //(90 > 83) so break
break;
}

//we did two passes in the loop so position is 1 so we return array[1]---> 1
1
ответ дан j2emanue 19 August 2018 в 01:08
поделиться

Я предлагаю использовать непрерывную проверку вероятности и остальной части случайного числа.

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

Вероятности должны суммироваться с одним.

function getRandomIndexByProbability(probabilities) {
    var r = Math.random(),
        index = probabilities.length - 1;

    probabilities.some(function (probability, i) {
        if (r < probability) {
            index = i;
            return true;
        }
        r -= probability;
    });
    return index;
}

var i,
    probabilities = [0.8, 0.1, 0.1],
    count = probabilities.map(function () { return 0; });

for (i = 0; i < 1e6; i++) {
    count[getRandomIndexByProbability(probabilities)]++;
}

console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }

0
ответ дан Nina Scholz 19 August 2018 в 01:08
поделиться

Вот 3 решения в javascript, так как я не уверен, на каком языке вы его хотите. В зависимости от ваших потребностей один из первых двух может работать, но третий, возможно, проще всего реализовать с большими наборами чисел .

function randomSimple(){
  return [0,0,0,0,0,0,0,0,1,2][Math.floor(Math.random()*10)];
}

function randomCase(){
  var n=Math.floor(Math.random()*100)
  switch(n){
    case n<80:
      return 0;
    case n<90:
      return 1;
    case n<100:
      return 2;
  }
}

function randomLoop(weight,num){
  var n=Math.floor(Math.random()*100),amt=0;
  for(var i=0;i<weight.length;i++){
    //amt+=weight[i]; *alternative method
    //if(n<amt){
    if(n<weight[i]){
      return num[i];
    }
  }
}

weight=[80,90,100];
//weight=[80,10,10]; *alternative method
num=[0,1,2]
8
ответ дан qw3n 19 August 2018 в 01:08
поделиться

Создайте случайное число R между 0 и 1.

Если R в [0, 0.1) -> 1

Если R в [0,1, 0,2) -> 2

Если R в [0.2, 1] -> 3

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

(1, 83,7%) и (2, 16,3%), сверните число от 1 до 1000. 1-837 - это 1. 838-1000 - это 2 .

18
ответ дан Thomas Eding 19 August 2018 в 01:08
поделиться
  • 1
    Это, по сути, то, что я собирался написать, но с кодом. – Sammy Larbi 8 December 2011 в 19:47
  • 2
    Мой друг придумал этот вариант этого подхода: return Math.random () & lt; 0,8? 0: (Math.random () & lt; 0,9? 1: 2); – Todd Sharp 8 December 2011 в 21:13
  • 3
    Я бы не рекомендовал это, если вы не имеете дело с условными вероятностями, которые лучше всего подходят для моделей. – Thomas Eding 8 December 2011 в 21:40
  • 4
    @ToddSharp Я знаю, что это древний, но ... вы действительно хотите использовать одно и то же случайное число, или вы получите предвзятость: r = Math.random (); return (r & lt; 0,8)? 0: (r & lt; 9)? 1: 2. В вашем коде «2» будет возвращаться только в том случае, если r1 & gt; = 8 и r2 & gt; = 9, что составляет 10% от 20% или 2% случаев. – jimm101 6 July 2016 в 20:37

Я использую следующее

function weightedRandom(min, max) {
  return Math.round(max / (Math.random() * max + min));
}

. Это мое «взвешенное» случайное значение, в котором я использую обратную функцию «x» (где x является случайным между min и max) до генерировать взвешенный результат, где минимум - самый тяжелый элемент, а максимальный - самый легкий (наименьший шанс получить результат)

. Таким образом, в основном, используя weightedRandom(1, 5), шансы получить 1 выше чем a 2, которые выше, чем 3, которые выше, чем 4, что выше, чем 5.

Не может быть полезно для вашего варианта использования, но, вероятно, полезно для людей, отправляющих этот же вопрос. / g3]

После 100 итераций попробуйте, это дало мне:

==================
| Result | Times |
==================
|      1 |    55 |
|      2 |    28 |
|      3 |     8 |
|      4 |     7 |
|      5 |     2 |
==================
5
ответ дан Tom Roggero 19 August 2018 в 01:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: