假设我需要在[0,K]范围内的N个加密安全的伪随机整数。实现这一目标最明显的方式是N调用arc4random_uniform(3)
,这正是我正在做的事情。
但是,分析器告诉我,对arc4random_uniform(3)
的大量调用占用了整个执行时间的2/3,而且我真的需要让代码更快。这就是我计划提前生成一些随机字节(可能使用arc4random_buf(3)
)并随后逐位提取的原因。
对于K = 2,我可以简单地掩盖所需的位,但是当K不是2的幂时,事情变得毛茸茸。当然我可以使用一堆%=
和/=
,但后来我会有模数偏见。另一个问题是当N变得太大时,我不能再将整个缓冲区解释为整数并对其执行算术运算。
如果它是相关的,K将小于20,而N可能非常大,如数百万。
你可以使用模数运算符和除法,你只需要做一些额外的预处理。像往常一样生成您的数组。将P
作为K
的最大幂,小于或等于2^32
(其中^
表示取幂),并迭代你的数组,确保所有随机值严格小于P
。任何不是,用一个小于P
的新随机数替换。这将消除偏见。
现在要处理大型N
,你需要两个循环。第一个循环遍历数组中的元素,第二个循环从每个元素中提取多个随机数。如果P = k ^ e
,那么你可以从数组中的每个元素从e
中提取[0, k)
随机数。每次从元素中提取随机数时,都要对该元素执行k
的分层。
当然,这不一定需要是实际的循环。您可以存储两个变量(数组索引,子元素索引),并在调用函数时从array_index
元素中提取。如果sub_element_index == e
,然后将其重置为零并增加array_index
。从此数组元素中提取随机数并返回它。