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

JavaScript: Math.random: How to choose a random number between 190 and 255 "unevenly", not "evenly"?

本文关键字:不均匀 随机数 均匀 之间 何选择 random Math 选择 JavaScript      更新时间:2023-09-26

如果你想选择一个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 = midRange前面,并在if/else语句中放置attackPoint = highRange

第一个代码:

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

第一种改进方式:

您不需要为所有范围计算随机值,只需要选定的范围。此外,不必将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);

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

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

一种更有效的方法是"拉伸"你想要的可能性更大的范围,然后随机选择。类似于:

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

这个想法是用可能的结果填充attachValue数组,更频繁地放入所需值的多个副本,然后随机选择一个。

另一种方法是对随机值进行平方运算,然后转换为整数。平方比添加特定的拐点更有可能以某种方式使较小的值。根据您的应用程序,这可能会更好(或不更好)。

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

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

这似乎是正确的。

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

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