JavaScript Random Number
这可能比编程更符合数学问题。在JS中,我想要一个函数返回一个间隔内的随机整数,比如说1-6,这就是我发现的:
1 2 3 4 5 | // 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。我在纸上手工画了几个数字,结果很好!但我不明白为什么!
假设你已经了解了
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 与max 之间)的随机整数。
这很酷,但是如果我想要一个从1到2的"实数"呢?
答案是:"将你的[0,1]转化为[1,2]。
实际上,这意味着在结果中加1。
试试看——
在数学中,这被称为"映射"。也就是说,对于[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)的乘法,所以它是一个保持分布的映射。
这是有效的!
好吧,现在有点复杂了…将[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。
也就是说,
现在,最后一个技巧是……将[0,1]映射到任意范围[最小值,最大值]。
这里的秘密是将其重新写入[最小值,最小值+范围],其中范围=最大值-最小值。
在这里,您可以看到将范围[0,range]转换为[min,min+range]很简单——只需向其添加"min"。所以如果我有范围[0,范围],我想得到[min,min+范围],我会使用f(x)=x+min。
那么我们如何从[0,1]到[0,range)?
乘以范围!
F(x)=(x*范围)+最小值
现在将内容写回原始术语,使用range=max-min
F(x)=(x*(max min))+min
将实数从[0,1]转换为实数从[min,max]
剩下的(把它变成一个有用的整数)留给你
1 2 3 | 0 <= Math.random() < 1 => 0 <= Math.random() * 6 < 6 => 0 <= Math.floor( Math.random() * 6 ) <= 5 |
然后添加"min",使其看起来像这样:
在您的示例中,对于min=1,您将拥有1-6中的所有数字。
我希望现在很清楚。
以下是您的代码说明:
Math.random() 生成一个介于0和1(不包括1)之间的随机数。- 您需要根据所需的数字范围缩放该值。您的范围是从您的
min 所需数字到您的max 所需数字(即max - min )的距离。 - 如果要在生成的数字范围内包含
max 值,则使用max - min + 1 。 - 然后,您需要确保随机数从正确的基数开始,而不是从
0 开始,因此您需要将min 添加到该基数中。 - 然后,如果您希望它是一个整数,您可以调用
Math.floor() 将其截断为下一个最低的整数。
所以,如果你有这个:
1 | Math.floor(Math.random()) |
你总是会得到零。因为0到1(不包括1)之间的浮点值的
然后,如果扩展范围:
1 | Math.floor(Math.random() * (max - min + 1)) |
现在您将得到一个介于0和
所以,为了让它从正确的基础开始,您添加了这样的
1 | Math.floor(Math.random() * (max - min + 1)) + min |