Пришел сюда по ссылке из расширения диапазона поплавков. Этот веселее. Вместо того, как я пришел к выводу, мне пришло в голову, что для данной случайной целочисленной производящей функции f
с «основанием» b (4 в этом случае, я расскажу почему), она может быть расширено, как показано ниже:
(b^0 * f() + b^1 * f() + b^2 * f() .... b^p * f()) / (b^(p+1) - 1) * (b-1)
Это преобразует генератор случайных чисел в генератор FLOAT. Я определю 2 параметра здесь b
и p
. Хотя «основание» здесь равно 4, b на самом деле может быть любым, это также может быть иррациональное число и т. Д. p
, я называю точность - это степень того, насколько хорошо вы хотите, чтобы ваш генератор с плавающей запятой был. Думайте об этом как о количестве вызовов, сделанных на rand5
для каждого вызова rand7
.
Но я понял, что если вы установите b в значение base + 1 (в данном случае это 4 + 1 = 5), это хорошее место, и вы получите равномерное распределение. Сначала избавьтесь от этого генератора 1-5, это на самом деле rand4 () + 1:
function rand4(){
return Math.random() * 5 | 0;
}
Чтобы попасть туда, вы можете заменить rand4
на rand5()-1
Далее следует преобразовать rand4 из целочисленного генератора в генератор с плавающей запятой
function toFloat(f,b,p){
b = b || 2;
p = p || 3;
return (Array.apply(null,Array(p))
.map(function(d,i){return f()})
.map(function(d,i){return Math.pow(b,i)*d})
.reduce(function(ac,d,i){return ac += d;}))
/
(
(Math.pow(b,p) - 1)
/(b-1)
)
}
Это применит первую написанную мной функцию к данной функции rand. Попробуйте:
toFloat(rand4) //1.4285714285714286 base = 2, precision = 3
toFloat(rand4,3,4) //0.75 base = 3, precision = 4
toFloat(rand4,4,5) //3.7507331378299122 base = 4, precision = 5
toFloat(rand4,5,6) //0.2012288786482335 base = 5, precision =6
...
Теперь вы можете преобразовать этот диапазон с плавающей запятой (0-4 INCLUSIVE) в любой другой диапазон с плавающей запятой, а затем понизить его до целого числа. Здесь наша база 4
, потому что мы имеем дело с rand4
, поэтому значение b=5
даст вам равномерное распределение. По мере того, как b растет за 4, вы начнете вводить периодические пробелы в распределении. Я протестировал значения b в диапазоне от 2 до 8 с 3000 баллами в каждом и по сравнению с нативным Math.random из javascript, выглядит для меня даже лучше, чем сам нативный:
http://jsfiddle.net/ibowankenobi/r57v432t/
Для ссылки выше, нажмите на кнопку «bin» в верхней части дистрибутивов, чтобы уменьшить размер bin. Последний график является родным Math.random, четвертый, где d = 5, является равномерным.
После того, как вы получите свой диапазон с плавающей запятой, умножьте на 7 и бросьте десятичную часть или умножьте на 7, вычтите 0,5 и округлите:
((toFloat(rand4,5,6)/4 * 7) | 0) + 1 ---> occasionally you'll get 8 with 1/4^6 probability.
Math.round((toFloat(rand4,5,6)/4 * 7) - 0.5) + 1 --> between 1 and 7