我正在寻找实现随机数生成器的最佳方法,它将允许我控制从哪个范围返回生成的数字的概率。为了展示我想要实现的内容,这里有一张图片:
所以总结一下:
假设我的范围是400。一开始,我想要获得5%的概率得到0-20的数字。但是在某个时刻,我希望这个概率增加到50%。希望你能明白我的意思。
![不均匀随机分布](https://istack.dev59.com/iQrl9.webp)
我觉得你需要的是一种生成正态分布(或高斯分布)数字的方法(如果你不知道这是什么,请看维基百科页面)。
Box-Muller变换可以用于生成成对的正态分布数字。
这里是极坐标形式的Box-Muller变换的C++实现,应该很容易翻译成JavaScript。
// Return a real number from a normal (Gaussian) distribution with given
// mean and standard deviation by polar form of Box-Muller transformation
double x, y, r;
do
{
x = 2.0 * rand() - 1.0;
y = 2.0 * rand() - 1.0;
r = x * x + y * y;
}
while ( r >= 1.0 || r == 0.0 );
double s = sqrt( -2.0 * log(r) / r );
return mean + x * s * stddev;
其中mean是正态分布的均值,stddev是分布的标准差。这段代码来自我最近使用的MersesenneTwister C++类,你可以在Rick Wagner的页面中找到它。你可以在此页面上找到有关Box-Muller变换的更多有用信息。
嗯,根据您的原始内容,我有一个非常简单的算法来按比例生成数组中的范围,然后随机选择一个范围并在该范围内生成随机数。毫无疑问,如果需要,它可以进行优化,但对我而言它很有效。
看起来代码很多,但其中3/4是注释、测试数据和函数,实际的randomRange函数只有17行代码。
<script type="text/javascript">
function randomRange(dataArray) {
// Helper function
function getRandomInRange(s, f) {
return (Math.random() * (f-s+1) | 0) + s
}
// Generate new data array based on probability
var i, j = dataArray.length;
var oArray = [];
var o;
while (j--) {
o = dataArray[j];
// Make sure probability is an integer
for (i=0, iLen=o.probability|0; i<iLen; i++) {
oArray.push([o.rangeStart, o.rangeEnd]);
}
}
// Randomly select a range from new data array and
// generate a random number in that range
var oEnd = oArray.length;
var range = oArray[getRandomInRange(0, oArray.length - 1)];
return getRandomInRange(range[0], range[1]);
}
// Test data set. Probability just has to be
// representative, so 50/50 === 1/1
var dataArray = [
{
rangeStart: 0,
rangeEnd : 20,
probability: 1
},
{
rangeStart: 21,
rangeEnd : 400,
probability: 1
}
];
// Test function to show range and number is randomly
// selected for given probability
function testIt() {
var el0 = document.getElementById('div0');
var el1 = document.getElementById('div1');
function run() {
var n = randomRange(dataArray);
if (n <= 20) {
el0.innerHTML += '*';
} else {
el1.innerHTML += '*';
}
}
setInterval(run, 500);
}
</script>
<button onclick="testIt();">Generate random number</button>
<div>Numbers 0 - 20</div>
<div id="div0"></div>
<div>Numbers 21 - 400</div>
<div id="div1"></div>