如何制作一个一次接受一个值的排列函数?

2024-03-02

我正在寻找一个函数,它接受区间 0,1....N 中的 1 个数字,并返回同一区间中的排列值。

0、1、2、3、4、5 和 f(x) 的示例如下:

f(0)=5;
f(1)=1;
f(2)=0;
f(3)=4;
f(4)=2;
f(5)=3;

根据我的研究/理解,这是一个循环群,其中 f(x) 是它的全部基础。 但是,如果发现函数 f(x) = 911 * x % N 是我想要的示例,那么在使用它时会出现模式。 911 是一个很大的素数,通过改变它,我得到了另一种排列,但仍然出现了一些问题。我的愿望是结果是随机的。

我知道我可以使用 [ 0, 1, 2...N ].shuffle() 之类的东西预先生成排列,但就我而言,我不能这样做。

我有一项服务需要输入一个数值并返回排列后的值/位置。 N 设置在服务器端,这也是我正在寻找的功能。


请记住,我在这里描述的算法基于列表 [1, 2, ... N-1] (长度为 N-1)。如果您坚持使用列表 [0, 1, ..., N](长度为 N+1),请进行所需的细微修改。此外,为了简洁起见,我使用 % 操作数的方式与大多数编程语言略有不同:a % b 取 1 和 b 之间的值,而不是 0 和 b - 1 之间的值,但背后的主要思想当然没有改变,因此 a % b 的值为 1 和 b 之间的整数,与 a 模 b 一致。

如果您仔细阅读本文,您会很明显地发现,生成的随机播放根本不是随机的。然而,如果参数选择得当,模式将不容易识别(我的模幂运算的基本思想来自密码学,其中具有不可识别的模式和不可恢复的函数非常重要)。

这更多的是与语言无关的算法描述,而不是实际的编程解决方案。我不会详细介绍有效实施和您可能遇到的陷阱。我希望它仍然有帮助。我还在 python 中编写了其中的某些部分,因此我可以提供进一步的帮助,甚至在需要时分享我的代码,但这之前需要一些完成和重构。

使用求幂代替乘法来消除模式

您对 f(x) = t * x % N(您选择为 911)的初步尝试显示了一些模式,因为乘法保持线性(在它的“模数”含义中)。

如果您使用幂而不是乘法,您可以给人更多随机的感觉。像 f(x) = t ^ x % N 之类的东西。但是,必须明智地选择 t(就像在乘法情况下一样,成为 N 的互质),并且此公式给出的输出不会提供不同的结果仅在 N 为素数的情况下,不同 x 值的数字。

大学数学即将到来,请耐心等待,我会尽量保持简单。

我们需要使用原根。相关的维基百科文章 http://en.wikipedia.org/wiki/Primitive_root_modulo_n可能会有很大帮助,但基本思想是精心选择的基数的幂的余数取 1 到 N-1 之间的所有值。例如

3^1 = 3
3^2 = 9 = 2 (mod 7)
3^3 = 27 = 6 (mod 7)
3^4 = 81 = 4 (mod 7)
3^5 = 243 = 5 (mod 7)
3^6 = 729 = 1 (mod 7)

都是不同的(从这一点开始,这些值从头开始重复:3^7 = 3^1 (mod 7)、3^8 = 3^2 (mod 7),依此类推)。

所以,如果你的 N 是 7,那么 3 就可以很好地成为 t。对于 1 到 6 之间的 x 值,可以使用 f(x) = (3 ^ x) % 7。

这会产生以下 f:

f(1) = 3
f(2) = 2
f(3) = 6
f(4) = 4
f(5) = 5
f(6) = 1

引入转变,提供一些额外的随机效果

如果你稍微玩一下这个,你会注意到,N-1 总是被打乱为 1。如果你想避免这种情况,我们可以更进一步,选择一个任意数字 k 在求幂后添加。也就是说,使用 g(x) = (f(x) + k) % (N-1) = ((t ^ x) % N + k) % (N-1),在我们的示例中令 k 为 2,产生排列:

g(1) = 5
g(2) = 4
g(3) = 2
g(4) = 6
g(5) = 1
g(6) = 3

如何选择底座

现在你有了基本的感觉。但当 N 不是 7 时,一般如何使用呢?

问题的关键是选择参数 t,在我们的示例中为 3。

不幸的是,这通常是一个难题(数学家称之为寻找原根 https://math.stackexchange.com/questions/124408/finding-a-primitive-root-of-a-prime-number),据我所知,没有任何易于解释的开箱即用的解决方案。

但这只是问题的一部分。更可悲的是,如果 N 是合数,原根甚至不起作用。例如,如果 N=6,则不存在任何数字 t 的表达式 t^x modulo 6 取 1 到 5 之间的所有值。

不过解决这部分并不是太难。

复合 N 可以做什么

如果 N 是合数,我们应该找到一个稍大一点的质数 P,并以基于该质数的算法为基础,通过将越界数字替换为洗牌后的值(并在需要时进行迭代) 。

例如,如果 N 为 6,我们可以选择 P 为 7,并使用之前构造的 g(x)。

g(1) = 5 ok (5<=N-1 holds)                          h(1) = 5
g(2) = 4 ok                                         h(2) = 4
g(3) = 2 ok                                    =>   h(3) = 2
g(4) = 6 too large, using g(g(4)) = g(6) = 3        h(4) = 3
g(5) = 1 ok                                         h(5) = 1

为了安全起见,我给出了另一个 N=4 的例子,其中我们使用之前计算的 P=7 的解决方案。

g(1) = 5, g(5) = 1                                  h(1) = 1
g(2) = 4, g(4) = 6, g(6) = 3                   =>   h(2) = 3
g(3) = 2                                            h(3) = 2

现在应该清楚了。选择接近 N 的 P 是明智的,这样 g 的越界值就不需要进行太多的重新计算。

回到寻找t

所以我们剩下的唯一问题就是找到可以用作幂运算底数的原根。

如果我之前链接的页面上的数学引起了一些本能的厌恶,我有一些好消息给你:t 的可能好的值在区间 [2, N-1] 中是密集的,所以即使是随机猜测也可能有所帮助。

有一些详细信息如何有效地验证随机选择的 t 是否真的对链接页面上的我们有利,但除非您正在处理非常大的数字,否则您可以只进行求幂并检查数字 1 是否出现早于 ( t 的 N-1) 次方(也许您还记得我注意到 t^x=1 (mod N) 在 x=N-1 的情况下始终成立,因此 1 的较早出现会破坏唯一性)。

我建议在 N/2 左右寻找合适的 t(意味着数量级 - 对于 P=91367,t=54949 效果很好)。如果您选择的 t 太低(例如 t=2),您可以轻松发现由某些相邻 x 值求幂引起的模式(2+k、4+k、8+k...将出现在彼此)。如果 t 太接近 N,则在相同奇偶校验的连续 x 值中查看 f(x) 时,可能会出现类似的现象。 t 的一个好的选择应该涵盖这些模式,并以足够随机的结果结束。

Summary

再次,这是算法的步骤

(N 给定)

找到一个比 N 稍大的素数 P

选择 1 和 P-1 之间的任意数字 k

找到 t,它是 P 的原根

(对于给定的 x,输出随机 h(x) 是)

计算

f(x) = (t ^ x) % P

计算

g(x) = (f(x) + k) % (P-1)

计算

h(x) = g(x)                                       if g(x)<=N-1,
       iterate the calculations with x = g(x)     otherwise
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何制作一个一次接受一个值的排列函数? 的相关文章

  • 指针 (*argv[]) 的指针的指针算术?

    我知道foo bar 等于 foo bar 但是什么是 foo bar 等于 例如访问 argv 2 我对这一点的理解有些困惑 我认为可能是这样的 foo bar 但我不确定 如果这是一个简单的答案 我深表歉意 a b 相当于 a b 由于
  • Java中的字符算术

    在玩的过程中 我遇到了一些对我来说似乎很奇怪的事情 以下不是有效的 Java 代码 char x A x x 1 possible loss of precision 因为其中一个操作数是整数 所以另一个操作数被转换为整数 结果无法分配给字
  • CPU是如何做减法的?

    我有一些基本的疑问 但每次我坐下来尝试面试问题时 这些问题和我的疑问就会出现 假设 A 5 B 2 假设A和B都是4字节 那么CPU是怎么做的呢 A B添加 我知道 A 的符号位 MSB 为 0 表示正值 B 的符号位为 1 表示负整数 现
  • 四舍五入到 25、50、75、100

    我不是一个数学爱好者 所以我很难想出一个将小数四舍五入到 25 50 75 和 100 的计算方法 这不会是典型的四舍五入 因为小数不会减少但只增加了 Example 如果 11 12 则舍入为 11 25 如果为 11 34 则舍入为 1
  • 用圆形雷达数学方法表示点

    我正在编写一个简单的应用程序 它可以向您显示您周围的朋友 但不是在法线地图中 而是在像 UI 这样的真正圆形雷达上 https i stack imgur com Au3IP png https i stack imgur com Au3I
  • 找出圆周上像素坐标的算法

    如果我知道圆心 圆半径和垂直角的像素坐标 如何找出圆圆周上一定角度的像素值 基本上 我试图在不同的时间绘制时钟的指针 1点 2点等 Let h是浮点数形式的小时 h 2 25将是 02 15 等 在 0 到 12 之间 cX cY 是中心的
  • 基于时间的算法评分

    我们希望创建一种评分算法 在更短的时间内获得更高的分数 在更长的时间内获得更少的分数 需要注意的是 没有实际范围 因此时间范围可以从 100 毫秒到长达 10 分钟或更长时间 点范围为 0 到 50 谢谢你的帮助 你可以简单地把它变成一个线
  • 使用数学符号注释 Adob​​e Reader PDF

    我阅读的许多数学教科书和其他文献都是 PDF 格式 因此我经常使用 Adob e Reader 注释工具对它们进行注释 我确实找到了一个有用的指南 http cjasn asnjournals org site misc annotatin
  • 具有非常大的数字的除法

    我只是想知道在处理大数字时有哪些不同的除法策略 我所说的大数字是指 50 位数字 例如 9237639100273856744937827364095876289200667937278 82637448262718273966299344
  • 如何在Python中显示坐标网格线的变换?

    假设我有常规的笛卡尔坐标系 x y 并且我考虑一个矩形网格区域 D 分成小方块 我想看看域 D 如何在 Python 中的坐标变换 T x y gt u x y v x y 下映射 我正在寻找这样的东西 See here https mat
  • 如何安全地将 CGFloat 降低或提高到 int?

    我经常需要在地板或天花板上安装CGFloat to an int 用于计算数组索引 我永远看到的问题floorf theCGFloat or ceilf theCGFloat 是浮点不准确可能会带来麻烦 那如果我的CGFloat is 2
  • 在 C# 中存储矩阵值的快速且有用的方法

    我需要用 C 为 3D 引擎创建一个 4x4 矩阵类 我见过一些其他引擎将矩阵值存储在单个浮点成员变量 字段中 如下所示 float m11 m12 m13 m14 float m21 m22 m23 m24 float m31 m32 m
  • 如何自定义舍入形式

    我的问题可能看起来很简单 但仍然无法得到有效的东西 我需要自定义 Math round 舍入格式或其他格式以使其工作如下 如果数字是 1 6 他应该四舍五入到 1 如果大于或等于 1 7 他应该四舍五入到 2 0 对于所有其他带有 6 的小
  • 如何四舍五入到一半,始终为正方向? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如何实现以下舍入 0 0126083
  • python:查找围绕某个 GPS 位置的圆的 GPS 坐标的优雅方法

    我有一组以十进制表示的 GPS 坐标 并且我正在寻找一种方法来查找每个位置周围半径可变的圆中的坐标 这是一个例子 http green and energy com downloads test circle html我需要什么 这是一个圆
  • 如何确保整数除法始终向上舍入?

    我想确保如有必要 整数除法总是向上舍入 还有比这更好的方法吗 目前正在进行大量选角工作 int Math Ceiling double myInt1 myInt2 更新 这个问题是我2013年1月博客的主题 http ericlippert
  • 将名称字符串编码为唯一的数字

    我有一大堆名字 数以百万计 他们每个人都有一个名字 一个可选的中间名和一个姓氏 我需要将这些名称编码为唯一代表这些名称的数字 编码应该是一对一的 即一个名称只能与一个数字相关联 一个数字只能与一个名称相关联 对此进行编码的明智方法是什么 我
  • 如何在Python的SciPy中更改稀疏矩阵中的元素?

    我构建了一个小代码 我想用它来解决涉及大型稀疏矩阵的特征值问题 它工作正常 我现在要做的就是将稀疏矩阵中的一些元素设置为零 即最顶行中的元素 对应于实现边界条件 我可以调整下面的列向量 C0 C1 和 C2 来实现这一点 不过我想知道是否有
  • 查找其索引的乘积可被另一个数字 X 整除的对的数​​量

    给定一个数组和某个值 X 找到满足以下条件的对的数量 i lt j a i a j and i j X 0 Array size lt 10 5 我想这个问题有一段时间了 但只能想出蛮力解决方案 通过检查所有对 这显然会超时 O N 2 t
  • 埃拉托色尼筛法 - 实现返回一些非质数值?

    我用 Java 实现了埃拉托斯特尼筛法 通过伪代码 public static void sieveofEratosthenes int n boolean numArray numArray new boolean n for int i

随机推荐