伪随机数生成的基本原理就是根据一个初始值(随机数种子),经过一系列计算(可以很复杂也可以很简单)获得另一个数值。太简单了不罗嗦直接上代码:
local function random()
---@class random
local self = {}
local _seed = 11
local m = 2^31 --伪随机模
local a = 1103515245 --伪随机倍数
local b = 12345 --伪随机增量
function self.seed(seed)
_seed = seed
end
function self.next_seed()
_seed = (_seed * a + b) & m
end
-- [min, max]
function self.random(min, max)
if min == max then
return min
end
if min > max then
return 0
end
self.next_seed()
return _seed % (max - min + 1) + min
end
return self
end
return random
需要注意的是几个数值:伪随机模,伪随机倍数,伪随机增量并不是凭空而来的,为了是的伪随机足够的接近随机,计算得到的数值需要足够的接近平均分布。这就需要提到一个很有名的线性同余法(Linear Congruential Generator, LCG),即上文中的:
_seed = (_seed * a + b) & m
并满足:
<aside> 💡 附上一条的相关讨论:https://stackoverflow.com/questions/8569113/why-1103515245-is-used-in-rand
</aside>
那么 a, b, m 的数值应该怎么取呢?下面这篇文章给出了几组取值,及相应的研究:
TL;DR:
文章 1.1 中提出的就是 ANSIC 中使用的 1103515245 和 12345 这个最经典的取值组合,至于 m 的取值为何是 2^31 这个值,主要考虑到实际需求上需要随机数的跨度范围足够大,或者说精度足够高,如果没有那么因此 m 够用即可(比如 2^16)。