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

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


当前回答

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

这给出了偏向50的分布,就像滚动两个骰子偏向7一样。

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

function weightedRandom(max, numDice) {
    let num = 0;
    for (let i = 0; i < numDice; i++) {
        num += Math.random() * (max/numDice);
    }    
    return num;
}

JSFiddle: http://jsfiddle.net/797qhcza/1/

其他回答

当然这是可能的。随机抽取1-100。如果数字<30,则在1-100范围内生成数字,如果不在40-60范围内生成数字。

这个答案真的很好。但是我想针对不同的情况发布实现说明(我不懂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之间的随机数,并映射到所需的分布。在这个例子中,你可以取f(x)=-(1/25)x2+4x来得到在你的范围中间值最多的分布。

分布

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

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