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

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


当前回答

这个答案真的很好。但是我想针对不同的情况发布实现说明(我不懂JavaScript,所以我希望你能理解)。


假设每个范围都有范围和权重:

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

初始静态信息,可以缓存:

所有权重之和(样本为108) 范围选择边界。基本上就是这个公式:Boundary[n] = Boundary[n - 1] + weight [n - 1] and Boundary[0] = 0。样本的边界为{0,1,3,103,108}

一代数量:

从范围[0,所有权重之和]生成随机数N。 For (i = 0;i < size(border) && N > border [i + 1];+ + i) 取第i个范围,生成该范围内的随机数。


性能优化的附加说明。范围不需要按升序或降序排列,所以为了更快的范围查找,权重最高的范围应该排在前面,权重最低的范围应该排在最后。

其他回答

最好的方法是生成一个随机数,该随机数平均分布在某一组数字中,然后对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到166666之间的数字。然后,我们只需要把这个数字投影到我们的第二个集合,它在0到100之间。

我们知道我们生成的随机数是输入x在0到100之间的抛物线的积分。这意味着我们只需假设随机数是F(x)的结果,然后解出x。

在这种情况下,F(x)是一个三次方程,形式为F(x) = ax^3 + bx^2 + cx + d = 0,下列表述成立:

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

为x解出这个问题会得到你所寻找的实际随机数,它保证在[0,100]范围内,并且更接近中心而不是边缘。

这是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>

获取数字数组等并不是有效的。您应该采用一个映射,该映射采用0到100之间的随机数,并映射到所需的分布。在这个例子中,你可以取f(x)=-(1/25)x2+4x来得到在你的范围中间值最多的分布。

用这样的东西怎么样:

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>

我的编码方式允许你设置几个变量: 循环=结果的数量 Tries =函数在停止while循环之前尝试获得40-60之间的数字的次数

额外的好处:它使用do while!!这是最棒的

您可以编写一个函数,根据权重将[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>