此函数生成一个随机数,但概率曲线有利于较低范围:
function getRandomLowNumber(min=1,max=100,factor=1){
let num = getRandomDecimal(min,max);
let rollDiff = num - min;
let percent = (rollDiff) / (max - min);
percent = 1 - (1 - percent) / factor;
return Math.round(rollDiff * percent + min);
}
我希望它在因子决定曲线的地方工作,因此因子1表示沿最小和最大范围的所有数字都是同等可能的,但0.5表示下降,其中2是1和3的可能性的一半是2的可能性的一半,依此类推。我在动态地搞清楚它时遇到了很多麻烦。
答案 0 :(得分:1)
可以通过简单的算术功能来解决这个问题。该函数将用于将均匀分布的随机数映射到具有特殊分布的期望范围。
如果我们以0.5为例,每个后继者的概率为一半,我们得到一个类似的事件:
#1 2 3 4 5 6 7
0 0 0 0 1 1 2
表示min = 0,max = 2,与max = 3相似:
#1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
0 0 0 0 0 0 0 0 1 1 1 1 2 2 3
注意什么?在max = 2的情况下,该集合由7(2^3 - 1
)个元素组成,并且在max = 3的情况下,它是15(2^4 - 1
)。因此,对于任意最大值,我们需要获得具有2^(max+1) - 1
元素的事件集。
所以我们现在需要做的是
1 .. 2^(max+1)-1
(等于distrib)第一项任务很简单,只需致电getRandomNumber(1,2^(max+1)-1)
。
第二个是通过计算此随机数的基数2的对数并将差值从最大值建立到最大值来完成的:
// for max==3 you get:
// rndnum : 1 2 3 4 5 6 7 8 9'0'1'2'3'4'5
// expflr : 0 1 1 2 2 2 2 3 3 3 3 3 3 3 3
// rndres : 3 2 2 1 1 1 1 0 0 0 0 0 0 0 0
int rndnum = getRandomNumber(1, Math.pow(2, max+1) - 1);
int expflr = Math.floor(log2(rndnum));
int rndres = max - expflr;
如果min != 0
怎么办?
这很容易处理:我们只是从max中减去它并将其添加到最终结果中。
除了0.5以外的分布是什么?
我们在公式中看到的臭名昭着的2只是1/0.5
。对于任意值,我们将{2}替换为1/factor
(来自您主题的因子,范围从0独占到1)
集合中的事件数由(1/factor)^0 + (1/factor)^1 + (1/factor)^2 + ...
给出,等于((1/factor)^(max+1) - 1) / (1/factor - 1)
。
适用于任意min,max和factor的最终版本:
double base = 1.0 / factor;
int evtcnt = Math.floor(Math.pow(base, max-min+1) - 1) / (base-1));
int rndnum = getRandomNumber(1, evtcnt);
int expflr = Math.floor(logb((rndnum-1) * (base-1) + 1, base));
int rndres = max - expflr;
请注意,Java中不存在log2
和logb
,但您可以使用log10(val) / log10(2.0)
resp log10(val) / log10(base)
定义它们。
function logb(val, base) {
return Math.log10(val) / Math.log10(base);
}
function getRandomNumber(min,max){
return Math.floor(Math.random()*(max-min+1)+min);
}
function getRandomLowNumber(min, max, factor) {
var base = 1.0 / factor;
var evtcnt = Math.floor(Math.pow(base, max-min+1) - 1) / (base-1);
var rndnum = getRandomNumber(1, evtcnt);
var expflr = Math.floor(logb((rndnum-1) * (base-1) + 1, base));
var rndres = max - expflr;
return rndres;
}
function runit() {
var min = document.getElementById('input-min').value;
var max = document.getElementById('input-max').value;
var factor = document.getElementById('input-factor').value;
var times = document.getElementById('input-times').value;
var list = {};
for (let i = 0; i < times; i++) {
var number = getRandomLowNumber(min, max, factor);
if (typeof list[number] == 'number') {
list[number]++;
} else {
list[number] = 1;
}
}
console.log('Min: ', min);
console.log('Max: ', max);
console.log('Factor: ', factor);
console.log('Iterations: ', times);
console.log('List: ', list);
}
function runClippy() {
var name = 'Clippy';
if (clippy.load._data[name]) {
return;
}
clippy.load(name, function(agent) {
var animations = agent.animations();
$('.js-states').text(animations.join(' '));
agent.show();
agent.moveTo(400, 30);
agent.speak("Hello, I see you're trying to run this sample. My name is " + name + " and yacc sent me here to help.");
agent.moveTo(200, 100);
agent.speak("There are four input fields to put parameters.");
agent.moveTo(300, 50);
agent.gestureAt(-100,50);
agent.speak("The first two specify the minimum and maximum random value.");
agent.moveTo(90,50);
agent.gestureAt(0,-50);
agent.speak("I'll put starting values for you here.");
agent._addToQueue(function(complete) {
$('.input-min').val("1");
$('.input-max').val("100");
complete();
});
agent.gestureAt(-100,50);
agent.speak("The next field specifies the factor that will decrease the probability for each successor. It should range between 0 (exclusively) and 1. Let's try a value here.");
agent._addToQueue(function(complete) {
$('.input-factor').val("0.5");
complete();
});
agent.moveTo(550, 70);
agent.gestureAt(-100,50);
agent.speak("The final input field is used to specify the amount of random numbers to generate. I'll fill it in for you.");
agent._addToQueue(function(complete) {
$('.input-times').val("100");
complete();
});
agent.speak("Now, did you notice the big button at the bottom of the form? You can push it to start the calculation.");
agent.moveTo(50, 120);
agent.gestureAt(-100,50);
agent.moveTo(90,50);
agent.gestureAt(0,-50);
agent.speak("Be careful with the amount of calculations. If the task takes too long, it might be aborted.");
agent.moveTo(630, 200);
agent.speak("So, now you can start on your own calculation of randoms. Be sure to fill in the fields properly, so that min <= max, or 0 < factor <= 1. Our lab is so busy at the moment that we spared a few safety belts.");
agent._addToQueue(function(complete) {
$('.wmd-input').val("# What are you trying to achieve?");
complete();
});
agent.moveTo(400, 30);
agent.gestureAt(-100, 50);
agent.speak("Please describe in short what you are trying to achieve");
agent._addToQueue(function(complete) {
$('.wmd-input').val("# What are you trying to achieve?\n\n# What is the problem you're facing?");
complete();
});
agent.moveTo(400, 70);
agent.gestureAt(-100, 50);
agent.speak("Please describe the error you're getting, and/or post the error message you're getting");
agent._addToQueue(function(complete) {
$('.wmd-input').val("# What are you trying to achieve?\n\n# What is the problem you're facing?\n\n#Show the code causing the problem");
complete();
});
agent.moveTo(400, 90);
agent.gestureAt(-100, 50);
agent.speak("Please post the code that causes your problem. Try to post it without clutter or unrelated code.");
agent.speak("People who answer should be able to use your code to reproduce the error. Please lookup MVCE in the stack overflow help .");
agent.moveTo(630, 200);
});
}
$(document).ready(function(){
// $('.wmd-input').one('focus', function() {runClippy();});
$('.input-min').one('focus', runClippy);
$('.input-max').one('focus', runClippy);
$('.input-factor').one('focus', runClippy);
$('.input-times').one('focus', runClippy);
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel='stylesheet prefetch' href='https://cdn.rawgit.com/smore-inc/clippy.js/master/build/clippy.css'>
<!--link rel="stylesheet prefetch" href="https://cdn.sstatic.net/Sites/stackoverflow/all.css?v=b0fb54f66683"-->
<script src='https://cdn.rawgit.com/smore-inc/clippy.js/master/build/clippy.min.js'></script>
<div>
Min: <input value="0" id="input-min" class="input-min processed">
Max: <input value="100" id="input-max" class="input-max processed"><br>
Factor: <input value="0.5" id="input-factor" class="input-factor processed"><br>
#-Runs: <input value="1000000" id="input-times" class="input-times processed"><br>
<button style="float: center;" onclick="runit()">--- Run that algorithm ---</button>
</div>
&#13;