如何在javascript中生成随机数等于特定数字?

3

好的,我的问题是我有三个随机数生成器,我希望这三个从1到5随机生成的数字的值加起来等于9。例如,我随机生成了4、3和2。在另一个按钮点击上,我随机生成了5、3和1。我已经试图做到这一点,但就是想不出来。

        function statGen() {
            var x = document.getElementById("number");
            x.innerHTML = Math.floor((Math.random() * 5) + 1);
            var a = document.getElementById("agl");
            a.innerHTML = Math.floor((Math.random() * 4) + 1);
            var l = document.getElementById("lck");
            l.innerHTML = Math.floor((Math.random() * 3) + 1);
        }
 <button id="statbutton" onclick="statGen()">Get Numbers</button>       
        <p id="main">Main:</p>
        <p id="number"></p>
        <br/>
        <p id="Agl">Agl:</p>
        <p id="agl"></p>
        <br/>
        <p id="Lck">Lck:</p>
        <p id="lck"></p>

我曾尝试将其通过循环运行多次直到变成数字9,但这些尝试都失败了。


您需要定义这里所说的“随机”是什么意思。一种解释是“在所有三个数字1-5的排列中,它们总和为9,随机选择一个”。 这与从余下的数字中选择一个随机数,然后再选择第二个,第三个是完全不同的。 - Mark Peters
你的代码中最后一个数字不能是随机的。 - Ja͢ck
这个主题已经有一个很好的答案了,可以在https://dev59.com/-nI_5IYBdhLWcg3wF_B3找到。 - Martin Dubois
@MartinDubois 这个讨论涉及到另一个话题。 - Ja͢ck
由于总和必须等于9,因此只能使用随机数生成两个数字,第三个数字是前两个数字之和与9的差。对于第一个数字,最大值为5,很容易。如果第一个数字大于3,则第二个数字有条件限制。因此,您需要生成一个随机数,其最大值为5和8减去第一个数字之间的较小值。然后第三个数字是前两个数字之和与9的差。祝编码愉快! - Jason Cust
5个回答

1
到目前为止,所有的答案都没有良好的随机性质。通过选择第一个数字,然后是第二个,再是第三个,你会对极端值有很大的偏向。
让我用一个骰子的例子来说明。假设你想要掷三个骰子使它们相加等于8。如果你一个一个掷,那么最终得到的排列中[6, 1, 1]的概率是1/6。这是因为在你掷出6之后(概率为1/6),剩下可接受的数字只有1和1。
实际上,[6, 1, 1]并不是所有可接受的掷骰子结果中近似于1/6的。例如,从3开始可以得到[3, 1, 4]、[3, 2, 3]、[3, 3, 2]、[3, 4, 1]。因此,以3作为第一个数字的概率应该是6的四倍。但是这些其他方法并不是这样!
因此,有几种方法可以获得“好”的随机性。最简单的方法实际上就是掷三个“骰子”,如果结果不符合你的限制条件,就重新掷一遍。
function roll() {
   return Math.floor(Math.random() * 5 + 1); //1-5 uniformly
}

function chooseNumbers() {
   var x = 0, y = 0, z = 0;

   while (x + y + z !== 9) {
      x = roll();
      y = roll();
      z = roll();
   }
   return [x, y, z];
}

这种方法对于大多数情况来说非常快,但你最终会丢弃相当数量的结果。另一种选择是枚举(使用代码或手动方式)所有可能的排列,然后使用均匀随机数选择一个索引。
var permutations = [
   [5, 3, 1],
   [5, 2, 2],
   [5, 1, 3],
   [4, 4, 1],
   //...
   [1, 3, 5]
];

function chooseNumbers() {
   return permutations[Math.floor(Math.random() * permutations.length)];
}

是的。我完全没有考虑结果的“随机性”。我只是专注于满足基本要求。 - Seamus
我手动输入了所有的排列组合,但无法将它们显示出来。我使用了以下函数 getStats() { var permutations = document.getElementById("number"); permutations.innerHTML = [Math.floor(Math.random() * permutations.length)];} 但它不起作用。在数字应该出现的地方,它显示“NaN”。我对此很陌生,这让我感到困惑...谢谢您提供的方法。 - CrossKing
@CrossKing:我的方法是给你一个由3个随机数组成的数组。但你仍需要正确地在页面上显示它。首先,你正在使用“permutations”作为包含DOM元素“number”的变量。将其命名为不同的名称,因为它与你的数组变量冲突了。 - Mark Peters
@MarkPeters 好的,我认为我在某些情况下找到了一种方法来改进你的方法。 - Seamus

0

最后的随机数r3取决于r1r2,因此被认为是随机的。

    function statGen() {
        var x = document.getElementById("number");
        var r1=Math.floor((Math.random() * 9) + 1);
        var r2=Math.floor((Math.random() * (8-r1)) + 1);
        var r3=9-r1-r2;
        x.innerHTML = r1;
        var a = document.getElementById("agl");
        a.innerHTML = r2;
        var l = document.getElementById("lck");
        l.innerHTML = r3;
    }

1
与其他答案类似,这会基于一个不必要的限制条件来减少熵值,即r2必须小于5 - Mark Peters

0

像这样吗?(这是伪代码):

var first = Math.floor((Math.random() * 5) + 1);

var second = Math.floor((Math.random() * 8-first) + 1);

var third = Math.floor((Math.random() * 9 - (first+second);

如果您需要保证有3个数字,那么前两个数字的和应该小于等于8,除非您接受0作为第三个可能的数字。

1
我真的不太理解third的计算方式。难道它不应该只是9 - first - second吗? - Mark Peters
是的,应该的。当我写这段代码并复制/粘贴这三行时,我很累了。我已经编辑过了,以反映更好的第三个计算。 - Shazam

0

Mark Peters在他的回答中概述了两种方法。第一种方法是一种蛮力方法:生成三个随机数的组合,直到找到它们的和为9为止。第二种方法是将所有28个可能的排列列成表格,然后随机选择一个。

第一种方法可能会更慢,而第二种方法将消耗更多的内存。只要您只需要执行一次,并且所需的三个数字的总和很小(如9),那么使用哪种方法并没有太大区别。

但是,如果所需的总和很大,您可能需要采用不同的方法。假设所需的总和为100万。蛮力方法可能会非常慢。列出所有排列可能会消耗太多的内存(或磁盘空间,具体取决于实现方式)。

排列的总数是整数1到最大可能值的总和。可以通过使用数学堆栈交换中的这个方程式来快速计算该总和:

取第一个数和最后一个数的平均值,然后乘以数字的数量。
因此,在这种情况下,排列的总数将接近于1,000,000 x 500,000;大约500,000,000,000个排列。
因此,我们可以生成一个随机数n,并仅在给定所需总和的情况下计算第n个排列,而不是计算所有可能的排列。
function getPermutation( n, requiredSum) {
  var remainder = n;
  var step = requiredSum - 2;

  var firstNumber = 1;

  while(remainder > step){
    firstNumber++;
    remainder -= step;
    step--;
  }

  var secondNumber = remainder;

  var thirdNumber = requiredSum - firstNumber - secondNumber;

  return [ firstNumber, secondNumber, thirdNumber ];

}

Example here:

$(document).ready( function(){
  $("button").click( function() {
    $("div").text( JSON.stringify( get3Numbers(1000000) ) );
  });
});

function get3Numbers(requiredSum){
  var maximum = requiredSum - 2;

  var permutations = maximum * ( (maximum + 1.0) / 2.0);

  var randomNumber = Math.floor((Math.random() * permutations) + 1);

  var threeNumbers = getPermutation(randomNumber, requiredSum);

  var sumOfNumbers = threeNumbers[0] + threeNumbers[1] + threeNumbers[2];

  return {
    threeNumbers: threeNumbers,
    total:  sumOfNumbers
  };
}

function getPermutation( n, requiredSum) {
  var remainder = n;
  var step = requiredSum - 2;

  var firstNumber = 1;

  while(remainder > step){
    firstNumber++;
    remainder -= step;
    step--;
  }

  var secondNumber = remainder;

  var thirdNumber = requiredSum - firstNumber - secondNumber;

  return [ firstNumber, secondNumber, thirdNumber ];

}
div {
    border: 1px solid silver;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>&nbsp;</div>
<button>Get three numbers!</button>


-1

这是一种实现的方式。

function statGen() {
    var x = document.getElementById("number");
    var firstNumber = Math.floor((Math.random() * 5) + 1);
    x.innerHTML = firstNumber;
    var a = document.getElementById("agl");
    if (firstNumber == 5) {
        var secondNumber = Math.floor((Math.random() * 4) + 1);
    } else {
        var secondNumber = Math.floor((Math.random() * 5) + 1);
    }
    a.innerHTML = secondNumber;
    var l = document.getElementById("lck");
    l.innerHTML = 9-(firstNumber + secondNumber);
 }
 <button id="statbutton" onclick="statGen()">Get Numbers</button>       
        <p id="main">Main:</p>
        <p id="number"></p>
        <br/>
        <p id="Agl">Agl:</p>
        <p id="agl"></p>
        <br/>
        <p id="Lck">Lck:</p>
        <p id="lck"></p>


为什么将第二个数字限制在4以内? - Mark Peters
两个数字都需要限制在4以内,这样第三个数字才能够大于0。否则,就可能出现“5和4”的情况,这将导致第三个数字为0,甚至更糟的是,“5和5”的情况,这将超过限制。 - Katherine
啥?5 + 3 + 1 = 9。2 + 5 + 2 = 9。5 > 4。 - Mark Peters
那么你最坏的情况应该是根据第一个数字的结果来限制第二个数字。仅仅因为它可能不可接受而从未让数字超过4,这就抛弃了大量的可能性,包括在问题中明确标识的一个例子。 - Mark Peters
好的观点。如果您需要每个数字都在1-5之间,那么您必须根据前一个数字动态更改要求。例如,如果firstNumber是5,则secondNumber必须为4或更低,依此类推。 - Katherine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接