【问题标题】:In Python Dictionaries, how does ( (j*5)+1 ) % 2**i cycle through all 2**i在 Python 字典中, ( (j*5)+1 ) % 2**i 如何循环遍历所有 2**i
【发布时间】:2016-09-19 14:51:05
【问题描述】:

我正在研究 python 如何实现字典。 python字典实现中的一个方程涉及使用方程对空字典槽的伪随机探测

j = ((j*5) + 1) % 2**i

解释here

看了How are Python's Built In Dictionaries Implemented?这个问题,基本明白字典是怎么实现的了。

我不明白为什么/如何等式:

j = ((j*5) + 1) % 2**i   

循环遍历2**i 的所有剩余部分。例如,如果 i = 3 的总起始大小为 8。j 经历了循环:

0
1
6
7
4
5
2
3
0

如果起始大小为16,则循环:

0 1 6 15 12 13 2 11 8 9 14 7 4 5 10 3 0

这对于探测字典中的所有槽非常有用。 但为什么它会起作用?为什么j = ((j*5)+1) 起作用,而j = ((j*6)+1)j = ((j*3)+1) 却不起作用,它们都陷入了较小的周期。

我希望对此有更直观的理解,而不是 等式有效,这就是他们使用它的原因

【问题讨论】:

  • 因为 5 与 2^i 互质,所以LCM 是 5 * 2^i。
  • 引用上面几行:“请参阅有关随机数生成的任何文本以获取证据”:)
  • @OliverCharlesworth 通过该论点,那么 (j*3)+1 也应该有效。
  • Knuth 的“计算机编程的艺术:第 2 卷”对类似问题进行了广泛的处理,您可能会觉得有帮助。
  • 这只是一个无关紧要的 Python 问题,一个字典问题,甚至是一个编程问题。

标签: python algorithm dictionary linear-probing


【解决方案1】:

正如 Jasper 所暗示的,这与伪随机数生成器使用的原理相同,即 linear congruential generators。线性同余生成器是遵循关系X_(n+1) = (a * X_n + c) mod m 的序列。从维基页面,

一般 LCG 的周期最多为 m,并且对于因子 a 的某些选择要小得多。当且仅当:

  1. mc 是相对质数。
  2. a - 1 可以被 m 的所有质因数整除。
  3. 如果m 可以被4 整除,a - 1 可以被 4 整除。

很明显,5是满足这些要求的最小a,即

  1. 2^i 和 1 互质。
  2. 4 可以被 2 整除。
  3. 4 可以被 4 整除。

另外有趣的是,5 并不是唯一满足这些条件的数字。 9也可以。以m 为 16,使用j=(9*j+1)%16 产生

0 1 10 11 4 5 14 15 8 9 2 3 12 13 6 7

这三个条件的证明可以在第 5 页的the original Hull-Dobell paper 中找到,以及其他一些可能感兴趣的 PRNG 相关定理。

【讨论】:

  • 定理陈述中不能是“当且仅当”;例如将c = 0a 作为原始根模2^i 将得到一个完整的周期,但0m 不互质。
  • @kevmo314 感谢您的回复。我接受了这个作为正确答案,但我不确定我是否完全理解每一种情况。例如,在 a = 7、c = 1、m =13 的情况下,我得到的周期长度为 12 而不是 13,但这似乎满足了所有 3 个要求。另一方面,在 a = 7, c=1, m = 18 的情况下,它工作得很好,我得到了预期的 18 周期长度
  • 我想在我之前的评论中 m = 13 可能不满足条件 2,因为 13 没有素因数(因为它本身就是素数)
  • Knuth 顺便说一句。还提到“当 m 是不同素数的乘积时,只有 a = 1 会产生完整的周期”,所以这应该让您知道不要为 m 选择什么:)
  • @FairlyNerdy 您的跟进是正确的,13 的主要因素包括 13,其中 6 不能被整除。如果m 由不同的质因数组成,那么唯一的解决方案将是 a = 1,正如 @poke 所指出的那样。
猜你喜欢
  • 2017-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-18
  • 2022-01-13
  • 2021-09-20
  • 1970-01-01
相关资源
最近更新 更多