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)
我会把剩下的(把它变成一个有用的整数)留给你