我正在寻找一个混合函数,该函数给出间隔<0,n)的整数,从同一间隔返回看起来随机的整数。间隔大小n通常为2的复合非幂。我需要功能是一对一的。它只能使用O(1)内存,强烈建议使用O(1)时间。我不太担心输出的随机性,但从外观上看,它应该足够随机(请参阅下一段)。
我想将此功能用作实时渲染器中的像素改组步骤,以选择渲染像素的顺序(输出将在固定时间后显示,如果尚未完成,这会给我带来很大的噪音)但快速的部分预览)。间隔大小n将是渲染中的像素数(n = 1920 * 1080 = 2073600是典型值)。该函数必须是一对一的,这样我就可以确保完成后每个像素都被精确渲染一次。
我已经看过hash prospector使用的可逆构造块,但是这些块主要是针对2范围的幂的。
我唯一想到的另一种方法是乘以大质数,但是它并不能提供特别好的随机输出。
这里还有哪些其他选择?
答案 0 :(得分:1)
这是一种基于原始根对素数进行模运算的解决方案:
如果a
是原始根mod p
,则函数g(i) = a^i % p
是小于p
的非零元素的排列。这对应于Lehmer prng。如果为n < p
,则可以得到0, ..., n-1
的排列,如下所示:给定i
在该范围内,请先加1,然后反复乘以a
,得到结果mod { {1}},直到获得p
元素为止,此时将返回结果-1。
要填充详细信息,this paper包含一个表,该表给出一系列素数(所有素数均接近<= n
的幂)和选择的相应原始根,以便它们产生具有良好统计特性的生成器。这是该表的一部分,被编码为Python字典,其中的键是素数,原始根是值:
2
考虑到d = {32749: 30805,
65521: 32236,
131071: 66284,
262139: 166972,
524287: 358899,
1048573: 444362,
2097143: 1372180,
4194301: 1406151,
8388593: 5169235,
16777213: 9726917,
33554393: 32544832,
67108859: 11526618,
134217689: 70391260,
268435399: 150873839,
536870909: 219118189,
1073741789: 599290962}
(在一定范围内,如果需要扩大该范围,请参阅本文),您可以找到最小的n
,它可以工作:
p
一旦知道了def find_p_a(n):
for p in sorted(d.keys()):
if n < p:
return p, d[p]
和匹配的n
,以下函数就是p,a
的排列:
0 ... n-1
进行快速测试:
def f(i,n,p,a):
x = a*(i+1) % p
while x > n:
x = a*x % p
return x-1
n = 2073600
p,a = find_p_a(n) # p = 2097143, a = 1372180
nums = [f(i,n,p,a) for i in range(n)]
print(len(set(nums)) == n) #prints True
中的平均乘法数为f()
,在这种情况下为p/n
,并且永远不会超过1.011
(或自{ {1}}不是2
的精确幂。实际上,此方法与您的“乘以大质数”方法没有根本区别,但是在这种情况下,应更仔细地选择因子,并且有时有时需要多次乘法才能增加表面随机性。