【问题标题】:Mixing function for non power of 2 integer intervals2 个整数区间的非幂的混合函数
【发布时间】:2019-03-22 10:02:18
【问题描述】:

我正在寻找一个混合函数,它从区间

我想将此函数用作实时渲染器中的像素洗牌步骤,以选择渲染像素的顺序(输出将在固定时间后显示,如果尚未完成,这会给我带来噪音但快速部分预览)。间隔大小 n 将是渲染中的像素数(n = 1920*1080 = 2073600 将是一个典型值)。该函数必须是一对一的,这样我才能确保每个像素在完成时都只渲染一次。

我查看了 hash prospector 使用的可逆构建块,但这些主要针对 2 范围的幂。

我能想到的唯一其他方法是乘以大素数,但它并没有给出特别好的随机输出。

这里还有哪些其他选项?

【问题讨论】:

  • f(x) = (p*x+b) (mod n) 其中pgcd(p,n) = 1 的大素数? b 会让它看起来更随机。
  • 我试过了,效果不大:/
  • 如何使用具有 2 的幂的生成器,使用 2 的最小幂,即> n?丢弃超过n 的生成索引。平均而言,每 2 个输出中您将丢弃不到 1 个。如果生成器很快,那么这样使用它仍然会很快。
  • 映射会保持一对一吗?
  • Yes:例如,给定一个排列 0, 4, 7, 1, 5, 3, 2, 60-7,如果你丢弃超过 5 的值,你会得到排列 0, 4, 1, 5, 3, 20-5。将此视为过滤器。通过 0-7 的准随机方式产生通过 0-5 的准随机方式。这条路线有一些效率低下,但如果循环为 2 次方的生成器既快又分布良好,那么性能应该可以接受。

标签: math hash unsigned-integer


【解决方案1】:

这是一种基于原根模素数的解决方案:

如果a 是原始根模p,则函数g(i) = a^i % p 是小于p 的非零元素的排列。这对应于Lehmer prng。如果n < p,则可以得到0, ..., n-1的排列如下:给定i在该范围内,先加1,然后反复乘以a,取结果modp,直到得到一个元素即<= n,此时您返回结果 - 1。

为了填写详细信息,this paper 包含一个表格,其中给出了一系列素数(所有这些都接近2 的各种幂)和相应的原始根,它们被选择以便产生具有良好的生成器统计性质。这是该表的一部分,编码为 Python 字典,其中键是素数,原始根是值:

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,并且永远不会超过2(或稍大一些,因为p 不是@ 的精确幂987654348@)。在实践中,这种方法与您的“乘以大素数”方法没有根本不同,但在这种情况下,因子的选择更加谨慎,而且有时需要不止 1 次乘法来增加明显的随机性。

【讨论】:

  • 谢谢你的回答,看起来很有希望。 f的定义没有错误吗?您正在将 a 乘以某个值,但可能应该进行幂运算。
  • f() 中没有错误。求幂只是重复乘法。这个想法是对于某些ki+1 等于a^k % p——但你真的不需要知道k 是什么。 a*(i+1) % k 将与 a^(k+1) % p 相同。这样做是让每个计算都可以并行完成的关键。
  • 哇。效果很好,现在我只需要把头绕在它周围:-)
猜你喜欢
  • 1970-01-01
  • 2015-01-08
  • 2012-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多