在不知道前一个数字但知道当前索引(无变量赋值)的情况下生成随机数序列的简单函数?

Simple function to generate random number sequence without knowing previous number but know current index (no variable assignment)?

提问人:Luke Vo 提问时间:5/15/2019 最后编辑:Luke Vo 更新时间:2/7/2020 访问量:272

问:

是否有任何(简单的)随机生成函数可以在没有变量赋值的情况下工作?我读到的大多数函数都是这样的。但是,目前我有一个限制(来自SQLite),我根本不能使用任何变量。current = next(current)

有没有办法生成一个数字序列(例如,从 1 到 ),只有(序列中的当前数字索引)和?maxnseed

目前我正在使用它:

cast(((1103515245 * Seed * ROWID + 12345) % 2147483648) / 2147483648.0 * Max as int) + 1

随着 47 岁,是 .然而,对于某些种子来说,重复率太高(47 颗种子中有 3 颗)。maxROWIDn

在我的要求中,只要不是太多(<50%),重复就可以了。有没有更好的功能可以满足我的需求?

该问题有sqlite标签,但任何语言/伪代码都可以。

P.s:我尝试过将线性同余生成器与一些 a/c/m 三元组和 as 一起使用,但它效果不佳,甚至更糟。Seed * ROWIDSeed

编辑:我目前使用这个,但我不知道它来自哪里。价格看起来比我的好:

((((Seed * ROWID) % 79) * 53) % "Max") + 1

SQLite 优化 随机 语言不可知 种子

评论

0赞 Shawn 5/15/2019
Sqlite有...sqlite.org/lang_corefunc.html#randomrandom()
0赞 Luke Vo 5/15/2019
@Shawn是的,但据我所知,我不能使用任何 ,这很重要,因为我需要序列是可重复的。Seed
1赞 Lee Daniel Crocker 5/15/2019
您的 SQL 实现是否具有 MD5 或 SHA1 等哈希函数?将 rowid 的简单哈希值修改为正确的范围,应该可以很好地工作。
0赞 Luke Vo 5/15/2019
@LeeDanielCrocker这是一个有趣的想法,但遗憾的是没有。

答:

0赞 Peter O. 5/15/2019 #1

具有适当选择参数ac 和模数 m)的线性同余生成器将是一个全周期生成器,因此它在重复之前伪随机循环其周期内的每个整。虽然你以前可能尝试过这个想法,但你有没有考虑过 m 等价于你的情况?有关此类生成器的参数选择列表,请参见 L'Ecuyer, P., “Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure”, Mathematics of Computation 68(225),1999 年 1 月。max

请注意,在 SQLite 中实现这一点存在一些实际问题,特别是如果您的 SQLite 版本仅支持 32 位整数和 64 位浮点数(精度为 52 位)。也就是说,可能存在以下风险:

  • 如果整数的中间乘法超过 32 位,则溢出,并且
  • 如果中间乘法导致大于 52 位的数字,则精度损失。

另外,请考虑为什么要创建随机数序列:

  • 序列是否具有不可预测性?在这种情况下,仅使用线性全等生成器是不够的,您应该通过其他方式生成唯一标识符,例如将唯一数字与加密随机数组合在一起。
  • 以这种方式生成的数字是否会以任何方式暴露给最终用户?如果没有,则无需通过“洗牌”来混淆它们。

此外,根据您使用的 SQLite API(适用于您的编程语言),可能有一种方法可以编写自定义函数来将种子转换为随机唯一数。但是,细节很大程度上取决于特定的SQLite API。另一个答案显示了 Perl 的示例。ROWID

评论

0赞 Luke Vo 5/15/2019
LCG 的问题在于我从未见过不使用变量的实现(知道 x(n) 而不知道 x(n-1))。这是我现在的主要局限性。至于编程语言,我无法访问它(它在沙盒的上下文中,我只提供数据库)
0赞 Peter O. 5/15/2019
您的应用程序中是否有一个常量(例如,它总是数字 47)?此外,请考虑为什么需要使用“随机”唯一数字,而不仅仅是“唯一”数字。这些数字会以任何方式暴露给最终用户吗?这些数字必须是“不可预测的”,还是仅仅是唯一的?为什么不能使用序列号或数字来代替?maxROWID
0赞 Luke Vo 5/15/2019
啊,对不起,我忘记了那些。好吧,这与安全性无关,只要可以获得可接受的结果,它应该是轻松的。最大值不是真正的常数,但通常应该在 43-50 左右(但在某些情况下可能会更高,但不会很多)。它们不必是绝对唯一或随机的。
0赞 Peter O. 5/15/2019
好吧,那么:这个数字还不够满足你的目的吗?如果不是,为什么不呢?ROWID
0赞 Luke Vo 5/15/2019
井。。。我需要它们是随机的,并且可以在给定相同的种子数的情况下进行复制。
1赞 Severin Pappadeux 5/15/2019 #2

使用良好的哈希函数并将结果映射到 [1...max] 范围怎么样?

沿着这条线(在伪代码中)。 已添加到 SQLite 3.17。sha1

sha1(ROWID) % Max + 1

或者使用任何外部 C 代码进行哈希(murmur、chacha 等),如下所示

评论

0赞 Luke Vo 5/15/2019
可悲的是,我是 3.15.2,我处于沙盒环境中,不允许对 SQLite 引擎本身进行更新/更改。无论如何,谢谢,对于限制比我少的人来说,这是一个有效的解决方案。sqlite_version()
0赞 Severin Pappadeux 5/16/2019
@LukeVo 也许有可加载的模块?我对SQLite不是很熟悉。基本上,任何具有良好雪崩属性(en.wikipedia.org/wiki/Avalanche_effect)的体面哈希值都可以完成这项工作。
1赞 Antun Skuric 2/7/2020 #3

我不确定你是否还有同样的问题,但我可能会为你找到一个解决方案。 您可以做的是使用基于移位寄存器的伪随机 M 序列生成器。你只需要取足够高的原始多项式的阶数,你不需要真正存储任何变量。 有关更多信息,您可以查看 wiki 页面

您需要编写的只是原始多项式移位方程,我已经在在线编辑器中检查过,它应该很容易做到。我认为最简单的方法是使用二进制基础并使用 PRBS 序列,并且根据您将拥有的元素数量,您可以选择序列长度。例如,这是我从 wiki 页面获取的原始多项式 (PRBS15) 长度的实现(在那里你可以找到一直到 PRBS31 的原始多项式) 基本上你需要做的是:2^15 = 327682^31=2.1475e+09

SELECT (((ROWID << 1) | (((ROWID >> 14) <> (ROWID >> 13)) & 1)) & 0x7fff)

这种方法的优点是,如果采用周期长于ROWID最大值的PRBS序列,则将具有唯一的随机索引。很简单。:)

如果你在搜索原始多项式时需要帮助,你可以看看我的 github 存储库,它完全处理如何查找原始多项式和唯一的 m 序列。它目前是用 Matlab 编写的,但我计划在未来几天内用 python 编写它。

干杯!