【问题标题】:JavaScript Random Number [duplicate]JavaScript 随机数 [重复]
【发布时间】:2013-07-05 04:52:20
【问题描述】:

这可能比编程更数学问题。在 JS 中,我想要一个在区间内返回随机整数的函数,比如 1-6,这就是我发现的:

// Returns a random integer between min and max
// Using Math.round() will give you a non-uniform distribution!
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

如果我将其复制并粘贴到我的代码中,我会感到内疚。我不明白这一点: 为什么我们从最大值中减去最小值,加 1,将答案乘以 Math.random(),然后加上最小值。我厌倦了在纸上手动输入几个数字,它工作得很好!但我不明白为什么!

【问题讨论】:

标签: javascript math


【解决方案1】:

假设您已经了解Math.floorMath.random 的行为,以下是剩下的一步一步:

  • Math.random() ↝ 介于0(含)和1(不含)之间的随机数
  • Math.random() * max ↝ 介于0(包括)和max(不包括)之间的随机数
  • Math.floor(Math.random() * max)0(包括)和max(不包括)之间的随机整数
  • Math.floor(Math.random() * (max - min)) + min ↝ 介于min(包括)和max(不包括)之间的随机整数
  • Math.floor(Math.random() * ((max + 1) - min)) + min ↝ 介于min(含)和max+1(不含)之间的随机整数(介于minmax 之间)

【讨论】:

    【解决方案2】:

    Math.random() 会给你一个从 0 到 1 的“真实”数字(不包括 1.0)。

    这很酷,但是如果我想要一个从 1 到 2 的“真实”数字怎么办?

    答案:将您的 [0,1)“转换”为 [1,2)。

    实际上,这意味着将结果加 1。

    试试看——Math.random()+1 会给你一个从 1 到 2 的数字。

    在数学中,这被称为“映射”。也就是说——对于 [0,1) 中的每个可能的实数,找到一种方法将该实数“映射”到 [1,2) 中的另一个实数。也就是说,如果我给您 [0,1) 之间的任何实数,您应该能够映射该数字 - 将该数字应用于将返回 [1,2) 之间的数字的函数。

    在我们的例子中,函数 f(x) = x+1。

    你看到这给了我们 [1,2) 之间的随机数吗?可视化两个相邻的区间,并想象一条线从 [0,1) 中的每个点到 [1,2) 中对应的地图。现在,在 [0,1) ... 上选择一个随机点,然后沿着这条线走。您将沿着这条线到达 [1,2) 中的一个随机点!

    现在,从 [0,1) 到 [1,2) 的所有完整的一对一映射都会将 [0,1) 之间的随机数转换为 [1,2) 之间的随机数...但是并非所有人都会在 [1,2) 之间为您提供一个均匀分布的随机数。映射为您提供均匀分布的结果背后的数学有点复杂,但简而言之,如果您的映射只涉及加、减、乘和除以常数,那么从结果也将均匀分布的意义上说,它是“合法的”。

    所以,现在我们知道如何将 [0,1) 转换为 [1,2)。

    如果我想将 [0,1) 映射到 [0,2) 上怎么办?我不能再添加数字了...

    我将所有内容都乘以 2 怎么样?

    这应该可以工作——函数 f(x) = x*2 确实将 [0,1) 上的每个点映射到 [0,2) 上的一个点 —— 因为它只涉及乘以常数 ( 2),它是一个保持分布的映射。

    这行得通! Math.random()*2 会给你一个 0 到 2 之间的随机数。

    好的,现在有点复杂...将 [0,1) 转换为 [1,3)。

    乘以 2 不起作用... 0*2 = 0,这不在您的目标范围内。 添加一个不起作用...即使 0+1 在您的目标范围内并且 1+1 也在您的目标范围内,但您永远无法达到 3。

    如果我们不能将 [0,1) 转换为 [1,3),让我们尝试看看是否可以将其他东西转换为 [1,3)。

    [0,2) 怎么样?是的,我们可以这样做……函数 f(x) = x+1 完美地将 [0,2) 映射到 [1,3)。您可以将+ 视为“向上移动”范围。

    所以这里的解决方案很明确——首先,将 [0,1) 变为 [0,2),然后将 [0,2) 变为 [1,3)。

    我们已经知道第一个 (f(x) = x*2),并且我们计算出了第二个 (f(x) = x+1)。所以“组合”变换/映射是 f(x) = (x*2)+1。

    也就是说,Math.random()*2 + 1 会给你一个从 0 到 3 的数字。

    现在是最后一招...将 [0,1) 映射到任意范围 [min,max)。

    这里的秘诀是将其重写为 [min,min+range),其中 range = max-min。

    在这里您可以看到将范围 [0,range) 转换为 [min,min+range) 很简单——您只需在其中添加“min”。所以如果我有范围 [0,range),我想得到 [min,min+range),我会使用 f(x) = x+min。

    那么我们如何从 [0,1) 到 [0,range) ?

    乘以范围!

    f(x) = (x*range) + min

    现在用 range = max-min 将事情写回原始术语

    f(x) = (x*(max-min)) + min

    将实数从 [0,1) 转换为实数 [min,max)

    剩下的(把它变成有用的整数)留给你

    【讨论】:

    • 非常感谢你的好回答,我希望我的数学能和你一样好。如果有办法给 +100000000 票我会的!
    【解决方案3】:
    0 <= Math.random() < 1  =>
    0 <= Math.random() * 6 < 6 =>
    0 <= Math.floor( Math.random() * 6 ) <= 5   
    

    然后你添加 'min' 所以它看起来像这样:

    min &lt;= Math.floor( Math.random() * 6 ) &lt;= 5 + min

    在您的示例中,对于 min = 1,您将拥有 1-6 中的所有数字。

    我希望现在很清楚。

    【讨论】:

      【解决方案4】:

      以下是您的代码的解释:

      • Math.random() 生成一个介于 0 和 1 之间(不包括 1)的随机数。
      • 您需要根据所需的数字范围调整该值。您的范围是您的min 所需号码与max 所需号码之间的距离,即max - min
      • 如果要在生成的数字范围内包含max 值,请使用max - min + 1
      • 然后,您需要确保随机数从正确的基数开始,而不是从 0 开始,然后将 min 添加到其中。
      • 然后,如果您希望它是一个整数,您可以调用 Math.floor() 将其截断为下一个最小的整数。

      所以,如果你有这个:

      Math.floor(Math.random())
      

      你总是会得到零。因为Math.floor() 的浮点值介于 0 和 1(不包括 1)之间,将始终截断为 0。

      那么,如果你扩大范围:

      Math.floor(Math.random() * (max - min + 1))
      

      您现在会得到一个介于 0 和 max - min 之间的随机数,包括较大的值。

      所以,要让它从正确的基础开始,你可以像这样添加min

      Math.floor(Math.random() * (max - min + 1)) + min
      

      【讨论】:

        猜你喜欢
        • 2020-10-18
        • 1970-01-01
        • 1970-01-01
        • 2012-05-28
        • 2013-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-23
        相关资源
        最近更新 更多