获取一个专注于中心的随机数字

是否有可能得到一个1-100之间的随机数,并保持结果主要在40-60范围内? 我的意思是,它会很less出现这个范围,但我希望它主要在这个范围内… JavaScript / jQuery可以吗?

现在我只是使用基本的Math.random() * 100 + 1

最简单的方法是从0-50生成两个随机数并将它们相加。

这给了一个分布偏向50,同样的方式滚动两个骰子偏向7。

事实上,通过使用大量的“骰子” (正如@Falco所build议的) ,您可以更接近于钟形曲线:

 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/

你在这里有一些很好的答案给出具体的解决scheme 让我为你描述一般的解决scheme。 问题是:

  • 我有一个0或1之间的或多或less均匀分布的随机数的来源。
  • 我希望产生一个随机数字序列,遵循不同的分布。

解决这个问题的一般办法是计算你想要的分布的分位数函数,然后把分位数函数应用到你的统一源的输出。

分位数函数是所需分布函数积分倒数 。 分布函数是曲线的一部分下的面积等于随机select的项目在该部分中的概率的函数。

我举一个如何在这里做的例子:

http://ericlippert.com/2012/02/21/generating-random-non-uniform-data/

那里的代码是用C#编写的,但是这些原则适用于任何语言; 将解决scheme调整为JavaScript应该很简单。

以数字排列等效率不高。 你应该采取一个映射,采取0到100之间的随机数,并映射到你需要的分布。 所以在你的情况下,你可以取f(x)=-(1/25)x 2 +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> 

几年前,我需要解决这个问题,我的解决scheme比任何其他答案都容易。

我在边界之间生成了3个随机数并对它们进行平均。 这将结果拉向中心,但完全有可能到达四肢。

看起来很笨,但你可以使用兰特两次:

 var choice = Math.random() * 3; var result; if (choice < 2){ result = Math.random() * 20 + 40; //you have 2/3 chance to go there } else { result = Math.random() * 100 + 1; } 

当然有可能。 随机做一个1-100。 如果数字<30,那么如果在40-60的范围内没有生成,则生成1-100范围内的数字。

有很多不同的方法来产生这样的随机数字。 一种方法是计算多个均匀随机数的和。 你总结了多less个随机数和他们的范围将决定最终分配的外观。

你总结的数字越多,它就越偏向中心。 在你的问题中已经提出使用1个随机数总和 ,但是你注意到并不偏向该范围的中心。 其他答案build议使用2个随机数的总和或3个随机数的总和 。

通过获取更多随机数的总和,您可以获得更多的偏向于范围中心的偏见。 在极端情况下,您可以将99个随机数的总和分别为0或1.这将是一个二项式分布。 (二项分布在某种意义上可以看作是正态分布的离散版本)。 这在理论上仍然可以覆盖整个范围,但是它对中心有很大的偏见,所以你不应该期望看到它达到终点。

这种方法意味着你可以调整你想要的偏见。

怎么样使用这样的东西:

 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> 

您可以根据权重编写一个函数,将随机值映射到[0, 1) [1, 100][1, 100] 。 考虑这个例子:

按重量百分比计为0.0-1.0至1-100

在这里,值0.95映射到[61, 100]之间的值。
事实上,我们有.05 / .1 = 0.5 ,当映射到[61, 100] ,得到81

这是function:

 /* * 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的加权解决scheme。

 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> 

好的,所以我决定增加一个答案,因为我觉得我最后的答案,以及这里的大多数答案,使用某种半统计方式获得钟形曲线types的结果返回。 下面我提供的代码与掷骰子的方式相同。 因此,最难得到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> 

我build议使用beta版本来生成0-1之间的数字,然后将其扩展。 它非常灵活,可以创build许多不同的分布形状。

这是一个快速而脏的采样器:

 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); } 

针对这个问题的最佳解决scheme是BlueRaja – Danny Pflughoeft提出的解决scheme,但我认为更快更通用的解决scheme也值得一提。


当我必须产生满足两个要求的随机数字(string,坐标对等)

  1. 结果集相当小。 (不超过16K号码)
  2. 结果集是谨慎的。 (只有整数)

我通常从创build一个满足要求的数字(string,坐标对等)开始(在你的情况下:包含更多可能的数组的数组),然后select该数组的一个随机项。 这样,你只需要为每个项目调用一次昂贵的随机函数。

分配

  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); 

通用解决scheme

 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); } 

最好的办法是生成一个随机数字,这个数字在一定数量的数字中是相同的,然后在0到100之间的投影函数中投影更可能达到你想要的数字。

通常情况下,达到这个math方法是绘制你想要的数字的概率函数。 我们可以使用钟形曲线,但是为了更容易计算,我们只需使用翻转的抛物线。

让我们做一个抛物线,它的根在0和100没有扭曲。 我们得到以下等式:

 f(x) = -(x-0)(x-100) = -x * (x-100) = -x^2 + 100x 

现在,0到100之间的曲线下面的所有区域代表我们想要生成的数字的第一组。 在那里,这一代是完全随机的。 所以,我们所要做的就是find我们第一套的范围。

下界当然是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到16666之间的数字。 那么,我们只需要取这个数字,并将其投影到我们的第二组,这是在0和100之间。

我们知道我们生成的随机数是我们抛物线的一个积分,inputx在0和100之间。这意味着我们只需要假设随机数是F(x)的结果,并求解x。

在这种情况下,F(x)是一个三次方程,forms为F(x) = ax^3 + bx^2 + cx + d = 0 ,下面的叙述是正确的:

 a = -1/3 b = 50 c = 0 d = -1 * (your random number) 

解决这个问题给你的实际随机数,你正在寻找,这是保证在[0,100]范围内和更高的可能性接近中心比边缘。

这个答案真的很好 。 但是我想发布实现指令(我不是JavaScript,所以我希望你会明白)针对不同的情况。


假设你有每个范围的范围和权重:

 ranges - [1, 20], [21, 40], [41, 60], [61, 100] weights - {1, 2, 100, 5} 

初始静态信息,可以被caching:

  1. 所有重量之和(108个样本)
  2. 范围select边界。 它基本上是这个公式: Boundary[n] = Boundary[n - 1] + weigh[n - 1]Boundary[0] = 0 。 样本具有Boundary = {0, 1, 3, 103, 108}

号码生成:

  1. 从范围[0,所有权重的总和中生成随机数N )。
  2. for (i = 0; i < size(Boundary) && N > Boundary[i + 1]; ++i)
  3. 取第i个范围并在该范围内生成随机数。

性能优化的附加说明。 范围不必按照升序和降序顺序排列,因此对于重量最大的范围查找范围应该首先进行,最重要的一个应该是最后一个。

如果您可以使用gaussian函数,请使用它。 此函数返回average 0sigma 1正常数字。

这个数字的95%在average +/- 2*sigma 。 你的average = 50sigma = 5

 randomNumber = 50 + 5*gaussian()