JavaScript:Math.random:如何“不均匀地”选择190到255之间的随机数,而不是“均匀”?

时间:2015-12-10 09:45:18

标签: javascript random

如果你想选择190到255之间的随机数,期望均匀分布式结果,你需要的代码就像下面那样简单,对吗?

190 + Math.floor(Math.random() * 66);

但是如果你喜欢不均匀分布在190到255之间的结果怎么办?我的意思是,例如,数字越接近范围的下端(即190),选择数字的可能性就越高。

让我们假设代码返回一个随机数:

  • between 190 and 210 with a 70% probability.
  • between 211 and 230 with a 20% probability.
  • between 231 and 255 with a 10% probability.

我认为像这样的不均匀分布为选择随机数的行为增添了一种有趣的味道。

我用两种不同的方式为此编写代码,第二种采用更复杂的形式。几天前我开始学习编程,所以我写了它们,借鉴了我​​目前对JavaScript的了解。我想知道我是否可以更有效地表达它们。

顺便说一句,我有一个具体的问题:

1st Code中,我是否需要在var声明前面attackPoint = midRangeattackPoint = highRange前面放置if/else

第一个代码:

var lowRange = 190 + Math.floor(Math.random() * 21);
var midRange = 211 + Math.floor(Math.random() * 20);
var highRange = 231 + Math.floor(Math.random() * 25);

var randomHundred = 1 + Math.floor(Math.random() * 100);

if (randomHundred <= 70) {
    var attackPoint = lowRange;
}
else if (randomHundred <= 90) {
    var attackPoint = midRange;
}
else {
    var attackPoint = highRange;
}

console.log(attackPoint);

第二段代码:

var lowRange = 190 + Math.floor(Math.random() * 21);
var midRange = 211 + Math.floor(Math.random() * 20);
var highRange = 231 + Math.floor(Math.random() * 25);

var emptyArray = [];

for (var i = 0; i < 100; i++) {
    if (i < 70) {
        emptyArray.push(lowRange);
    }
    else if (i < 90) {
        emptyArray.push(midRange);
    }
    else {
        emptyArray.push(highRange);
    }
};

var attackPoint = emptyArray[Math.floor(Math.random() * 100)];

console.log(attackPoint);

5 个答案:

答案 0 :(得分:3)

第一道改进:

您不需要计算所有范围的随机值,您只需要所选范围。此外,不必将0..1范围转换为0..100。您可以直接处理0..1范围。

var q = Math.random(), attackPoint;

if (q < 0.7) {
    attackPoint = 190 + Math.floor(Math.random() * 21);
}
else if (q < 0.9) {
    attackPoint = 211 + Math.floor(Math.random() * 20);
}
else {
    attackPoint = 231 + Math.floor(Math.random() * 25);
}

console.log(attackPoint);

答案 1 :(得分:0)

关于你的具体观点,我不是Javascript专家,但我认为你需要:

var attackPoint;  // Declare, but do no initialize the variable.
if (randomHundred <= 70) {
    attackPoint = lowRange;
}
else if (randomHundred <= 90) {
    attackPoint = midRange;
}
else {
    attackPoint = highRange;
}

更有效的方式是涉及&#34;拉伸&#34;你希望更有可能的范围,然后随机选择。类似的东西:

var attackValues = []
for (var i = 190; i < 211; i++) {
    for (var j = 0; j < 7; j++) {
        attackValue.push(i);  // Seven values here.
    }
}
for (var i = 211; i < 231; i++) {
     attackValue.push(i); attackValue.push(i); // Two values here
}
for (var i = 231; i < 256; i++) {
     attackValue.push(i);  // Just one value here.
}

// The attackValue array could be calculated once and stored for repeated
// use if your inflection points stay constant.

var attackPoint = attackValue[ Math.floor(Math.random() * attackValue.length) ]

我们的想法是使用可能的结果填充attackValue数组,更频繁地输入您想要的值的多个副本,然后随机选择一个。

答案 2 :(得分:0)

另一种方法是做一些像平方随机值,然后然后转换为整数。与添加特定的拐点相比,Squaring更可能以更小的方式使更小的值。根据您的应用,可能更好(或不)。

答案 3 :(得分:0)

从编程风格来看,将概率表与生成随机数的逻辑分开是一种很好的形式。原因是概率和范围的确切细节可能会随着时间的推移而改变,但加权随机数的概念将保持不变。因此,一旦您的加权随机数代码发生变化,您就不希望一次又一次地改变它:

var table = [
    { probability:70, low:190, hi: 210},
    { probability:20, low:211, hi: 230},
    { probability:10, low:231, hi: 255}
]

function weightedRandom(table) {
    var total  = table.reduce(function(sum, line) {
        return sum + line.probability;
    }, 0);
    var select = Math.floor(Math.random() * total);
    for (var i = 0; i < table.length; i++) {
        var line = table[i];
        select -= table[i].probability;
        if (select < 0) {
            return (Math.floor(Math.random() * (line.hi - line.low)) +
                    line.low;)
        }
    }
}

for (var i = 0; i < 10; i++) {
    console.log(weightedRandom(table));
}

注意:如果您假设概率总是加到100,则可以简化上述代码。

当我跑步时,我得到:

237
228
239
209
193
218
213
193
245
214

这似乎是正确的。

答案 4 :(得分:0)

我认为这也许是一种可能的解决方案:

var number = Math.random();
var index  = Math.floor(number * 66) + 190;   
//answer:
console.log(Math.floor(number * dist(index) * 66) + 190);

function dist(index) {
   var retValue;    
   if (index < 210) {
        retValue = .7;
    }
    else if (number >= 210 && number < 230) {
        retValue = .2;
    }
    else {
        retValue = .1;
    }
    return retValue;
}