【问题标题】:Quick random shuffle function in plain C普通C中的快速随机洗牌功能
【发布时间】:2012-07-31 06:49:37
【问题描述】:

多年来我一直在考虑这个问题,但从未设法实现。我说的是一个快速、高效的 C 函数,它在输入中接受一个整数数值(例如 16 位),并在输出中给出完全不同的相同位大小的数字,但“考虑”所有数字已经给出了,虽然不是通过使用真实记忆,而是通过数学魔法。抱歉,英语不是我的母语,我的意思是函数应该随机一对一映射,但不能有任何重复。

我想象的可能的应用程序之一是像素交叉淡入淡出图形例程之一,您可以将屏幕上的旧图片逐个像素地替换为新图片。坐标应随机选择,一旦像素被替换,就不应再次寻址(无重复)。所有这一切自然而然地通过一个基于数学的小型、快速和高效的函数(使用内存很容易实现,但这不是我想要的)。

显然,“位反转”解决方案行不通,因为它看起来不是随机的。甚至交换例如第 3 位和第 11 位等.. 以创建更多“混乱”,反转一些位等.. 看起来不太好,所以我正在寻找一个纯数学的、真正随机的函数,可能能够至少 16 位,并且使用尽可能少的内存(没有预先计算的表,因为我最终使用的第一个应用程序是在微控制器系统上使用公共域硬件和软件制作老式游戏)。

你能帮忙吗?

【问题讨论】:

    标签: c function random shuffle


    【解决方案1】:

    还有一个选择是使用加密。由于加密是可逆的,因此每个加密都是唯一的。对于 64 位数字,请使用 DES。对于 16 位或 32 位数字,请使用 Hasty Pudding Cipher。您还可以将 Hasty Pudding 调整为任何所需的范围,而不仅仅是 2 的幂。

    【讨论】:

      【解决方案2】:

      您要查找的基本上是与您要交叉淡入淡出的像素数相对应的组的循环生成器。在最一般的情况下,这与您的组的大小是互质的。通过以像素数为模进行所有计算,您会得到外观随机性,而这实际上并不是随机的。

      假设您有一个大小为 32 的域,并从种子 5 开始。通过不断添加 15 的互质数,您将得到以下序列

      (5, 20, 3, 18, 1, 16, 31, 14, 29, 12, 27, 10, 25, 8, 23, 4,...)

      这对于您的要求可能看起来足够随机。

      【讨论】:

      • +1:听起来不错!现在 OP 如何找到他的域大小的互质数?
      • @AAT:根据Bézout's identity,您可以简单地使用domain_size/2 - 1
      • @wildplasser:还有9 + 15 != 14 ;)。更正了顺序。
      • 我同意这是一个更大的问题,特别是当“随机性”对于小互质数开始变得明显时。如果 32 位算术可用,最好选择与 32 位域互质的加密值(或 PRNG 中使用的)之一,例如线性同余生成器或经典 Mersenne Twister 中使用的那些。跨度>
      • 感谢大家的编辑,我的心算已经不是以前的样子了:)
      【解决方案3】:

      rand() 函数已经这样做了。虽然,它不是从输入中获取数字,而是获取由 srand() 初始化并随着每次调用 rand() 而更改的存储值。

      您可以查看rand() 的实现以获取您的功能,或者在random number generation 上了解更多信息。

      这里有一个提示:

      首先,了解modular arithmetic是什么。

      现在想象以下顺序:

      m = 13
      a = 7
      b = 0
      
      s = 5     s = (a*s + b) % m
      s = 9     s = (a*s + b) % m
      s = 11    s = (a*s + b) % m
      s = 12    s = (a*s + b) % m
      s = 6     s = (a*s + b) % m
      s = 3     s = (a*s + b) % m
      s = 8     s = (a*s + b) % m
      s = 4     s = (a*s + b) % m
      s = 2     s = (a*s + b) % m
      s = 1     s = (a*s + b) % m
      s = 7     s = (a*s + b) % m
      s = 10    s = (a*s + b) % m
      s = 5     s = (a*s + b) % m
      

      请注意,在这种情况下,我将b=0 设置为更容易找到序列。尽管如此,这个例子并不是很好,但你明白了要点。对于给定的m,如果可以选择ab,您可以获得看起来有点随机的数字。

      这样,你的函数需要做的就是(a * argument + b) % m

      【讨论】:

      • 我认为不会,即 srand() 可能有两个输入值,它们将返回相同的输出。另外,也许这是错误的,但我在某处读到 srand() 只能在程序中调用一次。
      • @user1570761,我不建议使用rand。我是说您的功能类似于rand 的工作方式。也就是说,您很可能可以在线找到 rand 的实现,并且可以将其调整到您的程序中,即将其算法应用于输入参数而不是全局变量。
      • 另外,srand 中的值不同,您将从数字循环中的不同位置开始。由于该循环涵盖了所有数字(我的没有,但真正的 rand() 有)并且不会对任何数字重复,因此您无法为两个不同的输入获得相同的值。
      【解决方案4】:

      先生,您非常需要哈希函数。尝试例如 a=(a*31)%0xffff;对于一个穷人。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-30
        • 2016-04-26
        相关资源
        最近更新 更多