1-100 사이의 난수를 얻고 결과를 주로 40-60 범위 내에서 유지할 수 있습니까? 내 말은, 그 범위를 거의 벗어나지 않지만 주로 그 범위 내에 있기를 원합니다 ... JavaScript / jQuery로 가능합니까?
지금은 basic을 사용하고 Math.random() * 100 + 1
있습니다.
1-100 사이의 난수를 얻고 결과를 주로 40-60 범위 내에서 유지할 수 있습니까? 내 말은, 그 범위를 거의 벗어나지 않지만 주로 그 범위 내에 있기를 원합니다 ... JavaScript / jQuery로 가능합니까?
지금은 basic을 사용하고 Math.random() * 100 + 1
있습니다.
답변:
가장 간단한 방법은 0-50에서 두 개의 난수를 생성하고 함께 더하는 것입니다.
이것은 두 개의 주사위 바이어스를 7쪽으로 굴리는 것과 같은 방식으로 50쪽으로 바이어스 된 분포를 제공합니다.
사실, @Falco가 제안한대로 많은 수의 "주사위" 를 사용하면 종 곡선에 더 가까운 근사치를 만들 수 있습니다.
function weightedRandom(max, numDice) {
var num = 0;
for (var i = 0; i < numDice; i++) {
num += Math.random() * (max/numDice);
}
return num;
}
JSFiddle : http://jsfiddle.net/797qhcza/1/
여기에는 구체적인 해결책을 제시하는 좋은 답변이 있습니다. 일반적인 해결책을 설명하겠습니다. 문제는:
이 문제에 대한 일반적인 해결책은 운동하는 것입니다 분위수 기능을 원하는 분포를 한 다음 균일 한 소스의 출력에 분위수 기능을 적용 할 수 있습니다.
Quantile 함수는 원하는 분포 함수 의 적분 의 역수 입니다 . 분포 함수는 곡선의 한 부분 아래에있는 영역이 무작위로 선택된 항목이 그 부분에있을 확률과 같은 함수입니다.
여기에 그렇게하는 방법에 대한 예가 나와 있습니다.
http://ericlippert.com/2012/02/21/generating-random-non-uniform-data/
코드는 C #에 있지만 원칙은 모든 언어에 적용됩니다. 솔루션을 JavaScript에 맞게 수정하는 것이 간단해야합니다.
숫자 등을 취하는 것은 효율적이지 않습니다. 0에서 100 사이의 난수를 사용하고 필요한 분포에 매핑하는 매핑을 사용해야합니다. 따라서 귀하의 경우 범위 중간에 가장 많은 값을 갖는 분포를 얻을 수 있습니다 .f(x)=-(1/25)x2+4x
숫자가 "범위를 벗어남"으로 설정되도록 "기회"를 설정하는 것과 같은 것을 할 수 있습니다. 이 예에서 20 % 확률은 1-100, 그렇지 않으면 40-60입니다.
$(function () {
$('button').click(function () {
var outOfBoundsChance = .2;
var num = 0;
if (Math.random() <= outOfBoundsChance) {
num = getRandomInt(1, 100);
} else {
num = getRandomInt(40, 60);
}
$('#out').text(num);
});
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button>Generate</button>
<div id="out"></div>
몇 년 전에이 문제를 해결해야했고 솔루션이 다른 답변보다 쉽습니다.
나는 경계 사이에 3 개의 무작위를 생성하고 평균을 냈습니다. 이것은 결과를 중심으로 끌어 당겨 지지만 사지에 완전히 도달 할 수있게합니다.
BellFactor
3 을 사용할 때 결과는 당신과 같습니다.
이러한 난수를 생성하는 방법에는 여러 가지가 있습니다. 이를 수행하는 한 가지 방법은 여러 개의 균일 한 난수의 합을 계산하는 것입니다. 합산 한 난수와 범위는 최종 분포의 모양을 결정합니다.
숫자가 많을수록 중앙을 향해 더 많이 편향됩니다. 귀하의 질문 에 1의 난수 의 합계를 사용하는 것이 이미 제안되었지만 눈에 띄는 것처럼 범위의 중심으로 편향되지 않습니다. 다른 답변은 2 개의 난수 의 합 또는 3 개의 난수 의 합을 사용하여 제안 합니다 .
더 많은 난수의 합을 취하면 범위 중심으로 더 편향 될 수 있습니다. 극단적으로 당신은 각각 0 또는 1 인 99 개의 난수의 합을 취할 수 있습니다. 그것은 이항 분포입니다. 이항 분포는 어떤 의미에서 정규 분포의 개별 버전으로 볼 수 있습니다. 이론 상으로는 전체 범위를 다룰 수 있지만, 중심에 대한 편향이 너무 커서 끝점에 도달 할 것으로 예상해서는 안됩니다.
이 접근 방식은 원하는 바이어스를 조정할 수 있음을 의미합니다.
이와 같은 것을 사용하는 것은 어떻습니까?
var loops = 10;
var tries = 10;
var div = $("#results").html(random());
function random() {
var values = "";
for(var i=0; i < loops; i++) {
var numTries = tries;
do {
var num = Math.floor((Math.random() * 100) + 1);
numTries--;
}
while((num < 40 || num >60) && numTries > 1)
values += num + "<br/>";
}
return values;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="results"></div>
내가 코딩 한 방식으로 몇 가지 변수를 설정할 수 있습니다 :
루프 = 결과 횟수
시도 = 함수가 while 루프를 통해 실행을 중단하기 전에 40-60 사이의 숫자를 얻으려고 시도하는 횟수
추가 보너스 : 그것은 동안 사용합니다 !!! 최고의 최고
당신은 사이에 임의의 값을 매핑하는 기능을 쓸 수 있습니다 [0, 1)
에 [1, 100]
무게에 따라. 이 예제를 고려하십시오.
여기서 0.95
값은 사이 의 값에 매핑됩니다 [61, 100]
.
실제로 우리는 .05 / .1 = 0.5
에 매핑 할 [61, 100]
때을 산출 81
합니다.
기능은 다음과 같습니다.
/*
* Function that returns a function that maps random number to value according to map of probability
*/
function createDistributionFunction(data) {
// cache data + some pre-calculations
var cache = [];
var i;
for (i = 0; i < data.length; i++) {
cache[i] = {};
cache[i].valueMin = data[i].values[0];
cache[i].valueMax = data[i].values[1];
cache[i].rangeMin = i === 0 ? 0 : cache[i - 1].rangeMax;
cache[i].rangeMax = cache[i].rangeMin + data[i].weight;
}
return function(random) {
var value;
for (i = 0; i < cache.length; i++) {
// this maps random number to the bracket and the value inside that bracket
if (cache[i].rangeMin <= random && random < cache[i].rangeMax) {
value = (random - cache[i].rangeMin) / (cache[i].rangeMax - cache[i].rangeMin);
value *= cache[i].valueMax - cache[i].valueMin + 1;
value += cache[i].valueMin;
return Math.floor(value);
}
}
};
}
/*
* Example usage
*/
var distributionFunction = createDistributionFunction([
{ weight: 0.1, values: [1, 40] },
{ weight: 0.8, values: [41, 60] },
{ weight: 0.1, values: [61, 100] }
]);
/*
* Test the example and draw results using Google charts API
*/
function testAndDrawResult() {
var counts = [];
var i;
var value;
// run the function in a loop and count the number of occurrences of each value
for (i = 0; i < 10000; i++) {
value = distributionFunction(Math.random());
counts[value] = (counts[value] || 0) + 1;
}
// convert results to datatable and display
var data = new google.visualization.DataTable();
data.addColumn("number", "Value");
data.addColumn("number", "Count");
for (value = 0; value < counts.length; value++) {
if (counts[value] !== undefined) {
data.addRow([value, counts[value]]);
}
}
var chart = new google.visualization.ColumnChart(document.getElementById("chart"));
chart.draw(data);
}
google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(testAndDrawResult);
<script src="https://www.google.com/jsapi"></script>
<div id="chart"></div>
다음은 3/4 40-60 및 1/4 범위 밖의 가중치 솔루션입니다.
function weighted() {
var w = 4;
// number 1 to w
var r = Math.floor(Math.random() * w) + 1;
if (r === 1) { // 1/w goes to outside 40-60
var n = Math.floor(Math.random() * 80) + 1;
if (n >= 40 && n <= 60) n += 40;
return n
}
// w-1/w goes to 40-60 range.
return Math.floor(Math.random() * 21) + 40;
}
function test() {
var counts = [];
for (var i = 0; i < 2000; i++) {
var n = weighted();
if (!counts[n]) counts[n] = 0;
counts[n] ++;
}
var output = document.getElementById('output');
var o = "";
for (var i = 1; i <= 100; i++) {
o += i + " - " + (counts[i] | 0) + "\n";
}
output.innerHTML = o;
}
test();
<pre id="output"></pre>
좋아, 그래서 나는 마지막 대답과 같은 느낌이 들기 때문에 다른 대답을 추가하기로 결정했습니다. 대부분의 대답은 벨 커브 형 결과 반환을 얻는 반 통계 방법을 사용합니다. 아래에서 제공하는 코드는 주사위를 굴릴 때와 같은 방식으로 작동합니다. 따라서 1 또는 99를 얻는 것이 가장 어렵지만 50을 얻는 것이 가장 쉽습니다.
var loops = 10; //Number of numbers generated
var min = 1,
max = 50;
var div = $("#results").html(random());
function random() {
var values = "";
for (var i = 0; i < loops; i++) {
var one = generate();
var two = generate();
var ans = one + two - 1;
var num = values += ans + "<br/>";
}
return values;
}
function generate() {
return Math.floor((Math.random() * (max - min + 1)) + min);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="results"></div>
베타 배포판을 사용하는 것이 좋습니다 를 0-1 사이의 숫자를 생성 한 다음 확장하십시오. 매우 유연하고 다양한 형태의 분포를 만들 수 있습니다.
빠르고 더러운 샘플러는 다음과 같습니다.
rbeta = function(alpha, beta) {
var a = 0
for(var i = 0; i < alpha; i++)
a -= Math.log(Math.random())
var b = 0
for(var i = 0; i < beta; i++)
b -= Math.log(Math.random())
return Math.ceil(100 * a / (a+b))
}
var randNum;
// generate random number from 1-5
var freq = Math.floor(Math.random() * (6 - 1) + 1);
// focus on 40-60 if the number is odd (1,3, or 5)
// this should happen %60 of the time
if (freq % 2){
randNum = Math.floor(Math.random() * (60 - 40) + 40);
}
else {
randNum = Math.floor(Math.random() * (100 - 1) + 1);
}
이 문제를 해결하는 가장 좋은 솔루션은 BlueRaja-Danny Pflughoeft가 제안한 솔루션 이지만 다소 빠르고 더 일반적인 솔루션도 언급 할 가치가 있다고 생각합니다.
두 가지 요구 사항을 충족시키는 난수 (문자열, 좌표 쌍 등)를 생성 해야하는 경우
나는 일반적으로 요구 사항을 충족시키는 숫자 배열 (문자열, 좌표 쌍 등)을 만드는 것으로 시작합니다 (귀하의 경우 : 더 가능성이 높은 숫자를 여러 번 포함하는 숫자 배열). 그런 다음 해당 배열의 임의 항목을 선택하십시오. 이런 식으로, 당신은 항목 당 한 번 비싼 랜덤 함수를 호출해야합니다.
분포
5% for [ 0,39]
90% for [40,59]
5% for [60,99]
해결책
var f = Math.random();
if (f < 0.05) return random(0,39);
else if (f < 0.95) return random(40,59);
else return random(60,99);
일반 솔루션
random_choose([series(0,39),series(40,59),series(60,99)],[0.05,0.90,0.05]);
function random_choose (collections,probabilities)
{
var acc = 0.00;
var r1 = Math.random();
var r2 = Math.random();
for (var i = 0; i < probabilities.length; i++)
{
acc += probabilities[i];
if (r1 < acc)
return collections[i][Math.floor(r2*collections[i].length)];
}
return (-1);
}
function series(min,max)
{
var i = min; var s = [];
while (s[s.length-1] < max) s[s.length]=i++;
return s;
}
40-60 또는 1-100의 난수 생성 여부에 도우미 난수를 사용할 수 있습니다.
// 90% of random numbers should be between 40 to 60.
var weight_percentage = 90;
var focuse_on_center = ( (Math.random() * 100) < weight_percentage );
if(focuse_on_center)
{
// generate a random number within the 40-60 range.
alert (40 + Math.random() * 20 + 1);
}
else
{
// generate a random number within the 1-100 range.
alert (Math.random() * 100 + 1);
}
gaussian
기능을 사용할 수 있으면 사용하십시오. 이 함수는 average 0
및sigma 1
.
이 수의 95 %가 안에 average +/- 2*sigma
있습니다. 당신 average = 50
, 그리고 sigma = 5
이렇게
randomNumber = 50 + 5*gaussian()
가장 좋은 방법은 특정 숫자 집합에 균등하게 분포 된 난수를 생성 한 다음 0과 100 사이의 집합에 투영 기능을 적용하여 투영이 원하는 숫자를 칠 가능성이 더 높다는 것입니다.
일반적으로이를 달성하는 수학적 방법은 원하는 숫자의 확률 함수를 플로팅하는 것입니다. 우리는 종 곡선을 사용할 수 있지만, 더 쉬운 계산을 위해 뒤집힌 포물선으로 작업 해 봅시다.
뿌리가 기울이지 않고 0과 100이되도록 포물선을 만들어 봅시다. 우리는 다음 방정식을 얻습니다.
f(x) = -(x-0)(x-100) = -x * (x-100) = -x^2 + 100x
이제 0에서 100 사이의 곡선 아래의 모든 영역은 숫자를 생성하려는 첫 번째 세트를 나타냅니다. 거기에서 세대는 완전히 무작위입니다. 따라서 우리가해야 할 일은 첫 번째 세트의 경계를 찾는 것입니다.
하한은 물론 0입니다. 상한은 100에서의 함수의 적분입니다.
F(x) = -x^3/3 + 50x^2
F(100) = 500,000/3 = 166,666.66666 (let's just use 166,666, because rounding up would make the target out of bounds)
따라서 0에서 166,666 사이의 숫자를 생성해야합니다. 그런 다음 그 숫자를 가져 와서 두 번째 세트 (0에서 100 사이)로 투사하면됩니다.
우리가 생성 한 난수는 입력 x가 0에서 100 사이 인 포물선의 일부 정수라는 것을 알고 있습니다. 즉, 난수가 F (x)의 결과라고 가정하고 x를 풀기 만하면됩니다.
이 경우 F (x)는 3 차 방정식이며 형식 F(x) = ax^3 + bx^2 + cx + d = 0
에서는 다음과 같은 내용이 적용됩니다.
a = -1/3
b = 50
c = 0
d = -1 * (your random number)
x에 대해이 문제를 해결하면 찾고있는 실제 임의의 숫자가 생성되며 [0, 100] 범위에 있고 가장자리보다 중앙에 가까울 가능성이 훨씬 높습니다.
이 답변은 정말 좋습니다 . 그러나 다른 상황에 대한 구현 지침을 게시하고 싶습니다 (JavaScript가 아니므로 이해하기를 바랍니다).
모든 범위에 대한 범위와 가중치가 있다고 가정하십시오.
ranges - [1, 20], [21, 40], [41, 60], [61, 100]
weights - {1, 2, 100, 5}
초기 정적 정보는 캐시 될 수 있습니다.
Boundary[n] = Boundary[n - 1] + weigh[n - 1]
과 같습니다 Boundary[0] = 0
. 샘플은Boundary = {0, 1, 3, 103, 108}
숫자 생성 :
N
[0, 모든 가중치의 합) 범위에서 난수를 생성하십시오 .for (i = 0; i < size(Boundary) && N > Boundary[i + 1]; ++i)
i
범위를 잡고 해당 범위에서 난수를 생성 하십시오 .성능 최적화에 대한 추가 참고 사항. 범위는 오름차순 또는 내림차순으로 정렬 할 필요가 없으므로 빠른 가중치 범위를 찾으려면 가중치가 가장 높은 범위 조회 범위가 먼저 시작되고 가중치가 가장 낮은 범위가 먼저 시작됩니다.