获取一个专注于中心的随机数

Dar*_*man 238 javascript random algorithm numbers

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

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

Blu*_*eft 397

最简单的方法是从0-50生成两个随机数并将它们加在一起.

这使得分布偏向50,同样地将两个骰子偏差朝向7滚动.

实际上,通过使用更多的"骰子" (如@Falco建议的那样),您可以更接近钟形曲线:

function weightedRandom(max, numDice) {
    var num = 0;
    for (var i = 0; i < numDice; i++) {
        num += Math.random() * (max/numDice);
    }    
    return num;
}
Run Code Online (Sandbox Code Playgroud)

加权随机数

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

  • 很好的答案,但是如果有人打算使用它来生成正态分布,那么效率非常低(并且您需要对其进行转换以获得所需的均值和标准差).一个更有效的选择是Box-Muller变换,如果你知道一些数学,它很容易实现和理解. (14认同)
  • 这是一个简单快速的解决方案,可以通过添加更多数字(例如4 x(0-25))轻松加权,并为您提供良好的分布曲线! (12认同)
  • 这是一个很棒的代码.我想我爱上了它.简单,快捷,高效; 很好的答案.感谢您发布此内容. (8认同)
  • @RaziShaban [随机变量](http://en.wikipedia.org/wiki/Random_variable)的研究是统计学的核心部分.事实上,当我们增加骰子时,我们接近正态分布是着名的[中心极限定理](http://en.wikipedia.org/wiki/Central_limit_theorem). (2认同)

Eri*_*ert 48

你在这里有一些很好的答案,提供具体的解决方案 让我为您描述一般解决方案.问题是:

  • 我有一个或多或少均匀分布的0到1之间随机数的来源.
  • 我希望生成一系列随机数,这些随机数遵循不同的分布.

这个问题的一般解决方案是制定出位数功能所需的分布,然后应用位数功能制服源的输出.

分位数函数是所需分布函数积分倒数.分布函数是曲线的一部分下面积等于随机选择的项目在该部分中的概率的函数.

我举一个如何这样做的例子:

http://ericlippert.com/2012/02/21/generating-random-non-uniform-data/

其中的代码在C#中,但原则适用于任何语言; 应该可以直接使解决方案适应JavaScript.

  • 我喜欢这种方法.可能想补充说,存在一个确实生成高斯(和其他非正态)分布的javascript库:http://simjs.com/random.html (2认同)

iCa*_*mba 36

取数组等等效率不高.您应该采用一个映射,该映射采用0到100之间的随机数并映射到您需要的分布.因此,在您的情况下,您可以采用在您的范围中间获得最多值的分布.f(x)=-(1/25)x2+4x

分配

  • 我会接受你的意见,因为这不是我的专业领域.你能调整功能并显示新曲线吗? (3认同)
  • 我们实际上并不知道需要什么分布."主要是40-60"对我来说意味着一个钟形曲线. (2认同)

Bit*_*ive 17

我可能会做一些事情,例如设置一个"机会",允许号码"超出界限".在这个例子中,20%的可能性是1-100,否则,40-60:

$(function () {
    $('button').click(function () {
        var outOfBoundsChance = .2;
        var num = 0;
        if (Math.random() <= outOfBoundsChance) {
            num = getRandomInt(1, 100);
        } else {
            num = getRandomInt(40, 60);
        }
        $('#out').text(num);
    });
    
    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<button>Generate</button>
<div id="out"></div>
Run Code Online (Sandbox Code Playgroud)

小提琴:http://jsfiddle.net/kbv39s9w/

  • 也许有更多统计细节的人可以纠正我,虽然这确实达到了OP所期待的(所以我投了票),但这不会真正选择20%的时间超出界限,对吗?在这个解决方案中,有20%的时间你有机会从1-100中选择#,其中包括40-60.这实际上不是(0.2*0.8)16%来选择超出界限,还是我错过了什么? (5认同)

Lef*_*fty 15

几年前我需要解决这个问题,我的解决方案比任何其他答案都容易.

我在界限之间生成了3个randoms并对它们进行了平均.这会将结果拉向中心,但完全有可能到达四肢.

  • 这比BlueRaja的答案更好/不同?在那里,他取(2,3,......你想要的任何数字)随机数的总和并取平均值.当你使用3的BellFactor`时,结果与你的相同. (7认同)
  • JavaScript实际上*是一个C系列语言......但是啊. (5认同)
  • 真?您认为JS和C之间没有任何相似之处吗?好吧,好吧,我只想说我不能说那些语言,也不能说Java,对我而言,与我熟悉的语言相比,它们都是相似的. (2认同)

max*_*890 14

看起来很愚蠢但你可以使用rand两次:

var choice = Math.random() * 3;
var result;

if (choice < 2){
    result = Math.random() * 20 + 40; //you have 2/3 chance to go there
}
else {
    result = Math.random() * 100 + 1;
}
Run Code Online (Sandbox Code Playgroud)


Luk*_*jnc 11

当然有可能.随机1-100.如果数字<30,则生成数字在1-100范围内,如果不在40-60范围内生成.


kas*_*erd 11

生成这样的随机数有很多种不同的方法.一种方法是计算多个均匀随机数的总和.您总和了多少随机数以及它们的范围将决定最终分布的外观.

你总结的数字越多,它偏向中心的次数就越多.在你的问题中已经提出使用1个随机数总和,但是你注意到并没有偏向范围的中心.其他答案建议使用2个随机数总和3个随机数总和.

通过获取更多随机数的总和,您可以获得更多偏向范围的中心.在极端情况下,你可以得到99个随机数的总和,每个数字都是0或1.这将是二项分布.(在某种意义上,二项分布可被视为正态分布的离散版本).理论上它仍然可以涵盖整个范围,但是它对中心有很大的偏见,你永远不应该期待它到达终点.

这种方法意味着您可以调整您想要的偏差.


ctw*_*els 8

用这样的东西怎么样:

var loops = 10;
var tries = 10;
var div = $("#results").html(random());
function random() {
    var values = "";
    for(var i=0; i < loops; i++) {
        var numTries = tries;
        do {
            var num = Math.floor((Math.random() * 100) + 1);
            numTries--;
        }
        while((num < 40 || num >60) && numTries > 1)
        values += num + "<br/>";
    }
    return values;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="results"></div>
Run Code Online (Sandbox Code Playgroud)

我编写它的方式允许你设置几个变量:
loops =结果
尝试次数=函数在停止运行while循环之前尝试获得40-60之间的数字的次数

额外奖励:它使用do !!! 令人敬畏的最佳状态


Sal*_*n A 8

你可以写一个随机值之间的映射功能[0, 1),以[1, 100]按重量.考虑这个例子:

按重量百分比计为0.0-1.0至1-100

这里,值0.95映射到之间的值[61, 100].
事实上,我们有.05 / .1 = 0.5,当映射到[61, 100],屈服81.

这是功能:

/*
 * Function that returns a function that maps random number to value according to map of probability
 */
function createDistributionFunction(data) {
  // cache data + some pre-calculations
  var cache = [];
  var i;
  for (i = 0; i < data.length; i++) {
    cache[i] = {};
    cache[i].valueMin = data[i].values[0];
    cache[i].valueMax = data[i].values[1];
    cache[i].rangeMin = i === 0 ? 0 : cache[i - 1].rangeMax;
    cache[i].rangeMax = cache[i].rangeMin + data[i].weight;
  }
  return function(random) {
    var value;
    for (i = 0; i < cache.length; i++) {
      // this maps random number to the bracket and the value inside that bracket
      if (cache[i].rangeMin <= random && random < cache[i].rangeMax) {
        value = (random - cache[i].rangeMin) / (cache[i].rangeMax - cache[i].rangeMin);
        value *= cache[i].valueMax - cache[i].valueMin + 1;
        value += cache[i].valueMin;
        return Math.floor(value);
      }
    }
  };
}

/*
 * Example usage
 */
var distributionFunction = createDistributionFunction([
  { weight: 0.1, values: [1, 40] },
  { weight: 0.8, values: [41, 60] },
  { weight: 0.1, values: [61, 100] }
]);

/*
 * Test the example and draw results using Google charts API
 */
function testAndDrawResult() {
  var counts = [];
  var i;
  var value;
  // run the function in a loop and count the number of occurrences of each value
  for (i = 0; i < 10000; i++) {
    value = distributionFunction(Math.random());
    counts[value] = (counts[value] || 0) + 1;
  }
  // convert results to datatable and display
  var data = new google.visualization.DataTable();
  data.addColumn("number", "Value");
  data.addColumn("number", "Count");
  for (value = 0; value < counts.length; value++) {
    if (counts[value] !== undefined) {
      data.addRow([value, counts[value]]);
    }
  }
  var chart = new google.visualization.ColumnChart(document.getElementById("chart"));
  chart.draw(data);
}
google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(testAndDrawResult);
Run Code Online (Sandbox Code Playgroud)
<script src="https://www.google.com/jsapi"></script>
<div id="chart"></div>
Run Code Online (Sandbox Code Playgroud)


wol*_*mer 7

这是在该范围之外的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();
Run Code Online (Sandbox Code Playgroud)
<pre id="output"></pre>
Run Code Online (Sandbox Code Playgroud)


ctw*_*els 6

好的,所以我决定添加另一个答案,因为我觉得我的最后答案,以及这里的大多数答案,使用某种半统计方式获得钟形曲线型结果返回.我在下面提供的代码与掷骰子的方式相同.因此,最难获得1分或99分,但最容易获得50分.

var loops = 10; //Number of numbers generated
var min = 1,
    max = 50;
var div = $("#results").html(random());

function random() {
    var values = "";
    for (var i = 0; i < loops; i++) {
        var one = generate();
        var two = generate();
        var ans = one + two - 1;
        var num = values += ans + "<br/>";
    }
    return values;
}

function generate() {
    return Math.floor((Math.random() * (max - min + 1)) + min);
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="results"></div>
Run Code Online (Sandbox Code Playgroud)


Nea*_*ltz 6

我建议使用beta发行版生成0-1之间的数字,然后进行扩展.它非常灵活,可以创建许多不同形状的分布.

这是一个快速而肮脏的采样器:

rbeta = function(alpha, beta) {
 var a = 0   
 for(var i = 0; i < alpha; i++)   
    a -= Math.log(Math.random())

 var b = 0   
 for(var i = 0; i < beta; i++)   
    b -= Math.log(Math.random())

  return Math.ceil(100 * a / (a+b))
}
Run Code Online (Sandbox Code Playgroud)


小智 5

var randNum;
// generate random number from 1-5
var freq = Math.floor(Math.random() * (6 - 1) + 1);
// focus on 40-60 if the number is odd (1,3, or 5)
// this should happen %60 of the time
if (freq % 2){
    randNum = Math.floor(Math.random() * (60 - 40) + 40);
}
else {
    randNum = Math.floor(Math.random() * (100 - 1) + 1);
}
Run Code Online (Sandbox Code Playgroud)


mg3*_*0rg 5

针对这个问题的最佳解决方案是BlueRaja提出的解决方案- Danny Pflughoeft,但我认为一个更快,更通用的解决方案也值得一提.


当我必须生成满足两个要求的随机数(字符串,坐标对等)

  1. 结果集非常小.(不大于16K的数字)
  2. 结果集是谨慎的.(仅限整数)

我通常首先创建一个满足要求的数字数组(字符串,坐标对等)(在您的情况下:包含多次可能的数字的数组数组.),然后选择该数组的随机项.这样,您只需每个项目调用一次昂贵的随机函数.