Показать сообщение отдельно
  #22 (permalink)  
Старый 29.07.2012, 02:30
Аватар для Дзен-трансгуманист
√₋̅₁̅
Отправить личное сообщение для Дзен-трансгуманист Посмотреть профиль Найти все сообщения от Дзен-трансгуманист
 
Регистрация: 18.06.2012
Сообщений: 385

oneguy,
Я понял, у меня вся фигня в том, что:

points[0, 0] приводит к result[0, 0, 1] (вероятность 25%)
points[1, 1] приводит к result[1, 0, 0] (вероятность 25%)
points[0, 1] и points[1, 0] одинаково приводят к result[0, 1, 0] (вероятность 50%)

function SplitNum (sum, summands, min) {

  if (summands < 1 || summands * min > sum) { return []; }
  var i, range = sum - summands * min, points = [], result = [];
  for (i=0; i<summands-1; i++) { points[i] = Math.floor(Math.random() * (range + 1)); }
  points.push(0, range);
  points.sort(function (a, b) { return a - b; });
  for (i=0; i<summands; i++) { result[i] = points[i+1] - points[i] + min; }
  return result;
}

function testDistribution (range, iterations) {

  var i, counter = [];
  for (i=0; i<range; i++) { counter[i] = 0; }
  for (i=0; i<iterations; i++) { counter[SplitNum(1, range, 0).indexOf(1)]++; }
  return counter;
}

alert(testDistribution(10, 10000));
В идеале распределение должно быть линейным, то есть все числа должны быть близки к 1000, но здесь явно имеем отклонение, близкое к среднеквадратическому.

Тогда просто перемешаем результат перед возвратом:
function SplitNum (sum, summands, min) {

  if (summands < 1 || summands * min > sum) { return []; }
  var i, range = sum - summands * min, points = [], result = [];
  for (i=0; i<summands-1; i++) { points[i] = Math.floor(Math.random() * (range + 1)); }
  points.push(0, range);
  points.sort(function (a, b) { return a - b; });
  for (i=0; i<summands; i++) { result[i] = points[i+1] - points[i] + min; }

  for (i=0; i<summands-1; i++) { // перемешиваем порядок слагаемых
    var j = Math.floor(Math.random() * (summands - i)) + i; // генерируем j в диапазоне [i; summands-1]
    var swap = result[i]; result[i] = result[j]; result[j] = swap; // меняем местами значения по индексам i и j
  }
  return result;
}

function testDistribution (range, iterations) {

  var i, counter = [];
  for (i=0; i<range; i++) { counter[i] = 0; }
  for (i=0; i<iterations; i++) { counter[SplitNum(1, range, 0).indexOf(1)]++; }
  return counter;
}

alert(testDistribution(10, 10000));
Теперь всё в порядке.

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

Гейзенберг, возможно, читал этот тред.
Ответить с цитированием