伪随机数生成的基本原理就是根据一个初始值(随机数种子),经过一系列计算(可以很复杂也可以很简单)获得另一个数值。太简单了不罗嗦直接上代码:

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 的数值应该怎么取呢?下面这篇文章给出了几组取值,及相应的研究:

https://www.researchgate.net/publication/2683298_A_Collection_of_Selected_Pseudorandom_Number_Generators_With_Linear_Structures

TL;DR:

文章 1.1 中提出的就是 ANSIC 中使用的 1103515245 和 12345 这个最经典的取值组合,至于 m 的取值为何是 2^31 这个值,主要考虑到实际需求上需要随机数的跨度范围足够大,或者说精度足够高,如果没有那么因此 m 够用即可(比如 2^16)。