这可能是比编程更多的数学问题。在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;
}
如果我将其复制并粘贴到我的代码中,我会感到内疚。我不明白这个: 为什么我们从max中减去min,加1,将答案乘以Math.random()然后加上min。我手动在纸上累了几个数字,它工作得很好!但我不明白为什么!
答案 0 :(得分:5)
假设您已经了解Math.floor
和Math.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
之间的随机整数(不包括)(min
与{{之间的 OR 1}}包括两者)答案 1 :(得分:3)
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]怎么办?我不能再添加数字......
我把所有东西乘以两个怎么样?
这应该有效 - 函数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,范围]转换为[min,min + range]很简单 - 只需添加“min”即可。所以,如果我有[0,范围]范围,并且我想获得[min,min + range],我会使用f(x)= x + min。
那么我们如何从[0,1)到[0,范围]?
乘以范围!
f(x)=(x *范围)+ min
现在使用range = max-min
将内容写回原始术语f(x)=(x *(max-min))+ min
会将[0,1]中的实数从[min,max]
转换为实数我会把剩下的(把它变成一个有用的整数)留给你
答案 2 :(得分:1)
以下是对您的代码的解释:
Math.random()
生成0到1之间的随机数(不包括1)。min
所需数字与max
所需数字max - min
的距离。max
值,请使用max - min + 1
0
,因此您需要添加min
。Math.floor()
将其截断为下一个最小整数。所以,如果你刚才有这个:
Math.floor(Math.random())
你总是会得到零。因为0到1之间的浮点值的Math.floor()
(不包括一个)将始终截断为0。
然后,如果您使用以下内容扩展范围:
Math.floor(Math.random() * (max - min + 1))
现在,您将获得0到max - min
之间的随机数,包括更大的值。
所以,要让它从正确的基础开始,你可以像这样添加min
:
Math.floor(Math.random() * (max - min + 1)) + min
答案 3 :(得分:1)
0 <= Math.random() < 1 =>
0 <= Math.random() * 6 < 6 =>
0 <= Math.floor( Math.random() * 6 ) <= 5
然后你添加'min'所以它看起来像这样:
min <= Math.floor( Math.random() * 6 ) <= 5 + min
在你的例子中,对于min = 1,你将拥有1-6中的所有数字。
我希望现在很清楚。