我可以使用两种方法中的一种来创建具有两个重要特征的伪随机数序列—(1)它在不同的机器上是可复制的,并且(2)序列在全部发出之前从不重复范围内的数字。我的问题是-这些方法中的任何一个在可移植性方面是否存在潜在的问题(操作系统、python版本等)?例如,当xxx为真时,是否有人知道我会在一个系统上得到一组结果,而在另一个系统上得到另一组结果?我并不是真的要征求关于使用哪种方法本身的建议,只要当z为真时我应该注意y系统上的x。我试过几个版本的Linux,都是64位的,它们看起来是一致的,但我无法轻松访问Windows或32位版本。请注意,它们产生的范围不同,但这对我来说是可以的。这些数字在人眼看来只是随机的。方法1使用本机python库函数从范围生成随机样本。如果我使用大范围(10米或10米以上),速度会很慢,但对于相对较小的范围来说是可以的,而且对于没有数学学位的人来说更容易理解:import randomrandom.seed(5)x = random.sample(range(10000,99999),89999)for i in range(10): print(x[i])方法2使用的算法不是来自python库:(https://en.wikipedia.org/wiki/Linear_congruential_generator)即使在大范围内,速度也非常快,但很难理解,因此很难发现以下潜在问题:def lcg(modulus, a, c, seed): while True: seed = (a * seed + c) % modulus yield seedm = 10000019c = int(m/2)a = 5653s = ag = lcg(m,a,c,s)for _ in range(10): print(next(g))注:我对其他选择持开放态度;最初的问题是在这里提出的:https://math.stackexchange.com/questions/3289084/generate-a-pseudo-random-predictable-non-repeating-integer-sequence-purely-math 最佳答案 大多数便携式版本,IMO,将是LCG,其周期等于机器的自然字号它对模块使用寄存器溢出,这使得它更快您必须使用numpy数据类型来实现这一点,下面是简单的代码,常数a、c取自表4hereimport numpy as npdef LCG(seed: np.uint64, a: np.uint64, c: np.uint64) -> np.uint64: with np.errstate(over='ignore'): while True: seed = (a * seed + c) yield seeda = np.uint64(2862933555777941757)c = np.uint64(1)rng64 = LCG(np.uint64(17), a, c)print(next(rng64))print(next(rng64))print(next(rng64))Linux x64和Windows x64以及OS X虚拟机的工作原理完全相同。关于可再现性,唯一的好处是存储前两个数字,并在应用程序初始化阶段将它们与lcg输出进行比较-如果它们正常,则继续。我喜欢的lcg的另一个特性是它能够在log2(n)时间内跳到前面,其中n是跳的次数。我可以给你提供代码使用向前跳转可以确保并行独立随机流的非重叠序列更新下面是将我的c代码翻译成python/numpy的过程,看起来很有用。它在对数时间上既可以向前跳,也可以向后跳。import numpy as npclass LCG(object): UZERO: np.uint64 = np.uint64(0) UONE : np.uint64 = np.uint64(1) def __init__(self, seed: np.uint64, a: np.uint64, c: np.uint64) -> None: self._seed: np.uint64 = np.uint64(seed) self._a : np.uint64 = np.uint64(a) self._c : np.uint64 = np.uint64(c) def next(self) -> np.uint64: self._seed = self._a * self._seed + self._c return self._seed def seed(self) -> np.uint64: return self._seed def set_seed(self, seed: np.uint64) -> np.uint64: self._seed = seed def skip(self, ns: np.int64) -> None: """ Signed argument - skip forward as well as backward The algorithm here to determine the parameters used to skip ahead is described in the paper F. Brown, "Random Number Generation with Arbitrary Stride," Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in O(log2(N)) operations instead of O(N). It computes parameters A and C which can then be used to find x_N = A*x_0 + C mod 2^M. """ nskip: np.uint64 = np.uint64(ns) a: np.uint64 = self._a c: np.uint64 = self._c a_next: np.uint64 = LCG.UONE c_next: np.uint64 = LCG.UZERO while nskip > LCG.UZERO: if (nskip & LCG.UONE) != LCG.UZERO: a_next = a_next * a c_next = c_next * a + c c = (a + LCG.UONE) * c a = a * a nskip = nskip >> LCG.UONE self._seed = a_next * self._seed + c_nextnp.seterr(over='ignore')a = np.uint64(2862933555777941757)c = np.uint64(1)seed = np.uint64(1)rng64 = LCG(seed, a, c) # initializationprint(rng64.next())print(rng64.next())print(rng64.next())rng64.skip(-3) # back by 3print(rng64.next())print(rng64.next())print(rng64.next())rng64.skip(-3) # back by 3rng64.skip(2) # forward by 2print(rng64.next())无论如何,LCG RNG摘要:有了好的常数(见L'ecuyer论文的引用),它将覆盖整个[0…264]范围,而不会重复自身。基本上完美的[0…264)>[0…264)映射,您可以设置0,1,2,3,…作为输入并获得整个范围的输出它是可逆的,你可以得到以前的种子,所以映射实际上是双射,[0…264)[0…264)。详见Reversible pseudo-random sequence generator。它有向前和向后的对数跳跃,所以没有问题适合并行计算的时间间隔-从单种子开始,然后下一个线程将被跳过(seed,264/n)、下一个线程跳过(seed,264/n*2)等等。保证不重叠它简单快速,虽然不是很高质量的RNG