random 实现了一个伪随机数生成器。知道了算法和参数,我们可以预测生成的序列。文末是linear pseudo random generator 在 Python 中的一个可能实现,它表明生成器可以是一个简单的线性函数。
os.urandom 使用系统熵源进行更好的随机生成。熵源是我们无法预测的,例如异步事件。例如,我们无法预测我们敲击键盘键的频率。
来自其他设备的中断也可能是不可预测的。
在 random 模块中有一个类:SystemRandom,它使用 os.urandom() 来生成随机数。
实际上,无法证明给定序列是随机的还是非随机的。 Andrey Kolmogorovwork this out 广泛存在于 1960 年代左右。
当在任何给定语言中获取序列的规则大于序列本身时,可以认为序列是随机的。以下面的序列为例,它看起来是随机的:
264338327950288419716939937510
但是我们也可以将其表示为:
pi 数字 21 到 50
由于我们找到了一种方法来表示比序列本身更小的序列,因此序列不是随机的。我们甚至可以想出一种更紧凑的语言来表示它,比如:
pi[21,50]
或者另一个。
但是用最紧凑的语言(或者更小的算法,如果你愿意的话)生成序列的更小的规则可能永远不会被发现,即使它存在。
这一发现仅取决于人类的智力,这不是绝对的。
可能有一种确定的方法来证明一个序列是否是随机的,但我们只有在有人找到它时才能知道它。或者也许没有办法证明随机性是否存在。
LCG(线性全等生成器)在 Python 中的实现可以是:
from datetime import datetime
class LCG:
defaultSeed = 0
defaultMultiplier = 1664525
defaultIncrement = 1013904223
defaultModulus = 0x100000000
def __init__(self, seed, a, c, m):
self._x0 = seed #seed
self._a = a #multiplier
self._c = c #increment
self._m = m #modulus
@classmethod
def lcg(cls, seed = None):
if seed is None: seed = cls.defaultSeed
return LCG(int(seed), cls.defaultMultiplier,
cls.defaultIncrement, cls.defaultModulus)
#pre: bound > 0
#returns: pseudo random integer in [0, bound[
def randint(self, bound):
self._x0 = (self._a * self._x0 + self._c) % self._m
return int(abs(self._x0 % bound))
#generate a sequence of 20 digits
rnd = LCG.lcg(datetime.now().timestamp()) #diff seed every time
for i in range(20):
print(rnd.randint(10), end='')
print()