在不知道前一个数字但知道当前索引(无变量分配)的情况下生成随机数序列的简单函数?
Simple function to generate random number sequence without knowing previous number but know current index (no variable assignment)?
是否有任何(简单的)随机生成函数可以在没有变量赋值的情况下工作?我阅读的大多数函数看起来像这样 current = next(current)
。但是目前我有一个限制(来自 SQLite)我根本不能使用任何变量。
有没有办法生成一个只有 n
(序列中的当前数字索引)和 seed
的数字序列(例如,从 1 到 max
)?
目前我正在使用这个:
cast(((1103515245 * Seed * ROWID + 12345) % 2147483648) / 2147483648.0 * Max as int) + 1
其中 max
为 47,ROWID
为 n
。然而,对于某些种子,重复率太高(47 个中有 3 个是唯一的)。
在我的要求中,重复是可以的,只要不是太多(<50%)即可。有没有更好的功能满足我的需求?
问题有sqlite标签,但任何language/pseudo-code都可以。
P.s:我曾尝试将 Linear congruential generators 与一些 a/c/m 三胞胎一起使用,并将 Seed * ROWID
用作 Seed
,但效果不佳,甚至更糟。
编辑:我目前使用这个,但我不知道它来自哪里。汇率看起来比我的好:
((((Seed * ROWID) % 79) * 53) % "Max") + 1
A linear congruential generator with appropriately-chosen parameters (a, c, 和模 m)将是一个 full-period 生成器,这样它在重复之前伪随机地循环遍历其周期中的每个整数。尽管您以前可能尝试过这个想法,但您是否考虑过m 等同于您的情况下的max
?有关此类生成器的参数选择列表,请参阅 L'Ecuyer, P., "Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure", Mathematics of Computation 68(225), January 1999.
请注意,在 SQLite 中实现此操作存在一些实际问题,特别是如果您的 SQLite 版本仅支持 32 位整数和 64 位 floating-point 数字(精度为 52 位)。也就是说,可能存在风险——
- 如果整数的中间乘法超过 32 位,则溢出,并且
- 如果中间乘法产生 greater-than-52 位数字,则精度损失。
此外,请考虑您创建随机数序列的原因:
- 这个顺序是不是故意设计成不可预测的?在这种情况下,仅线性同余生成器是不够的,您应该通过其他方式生成唯一标识符,例如 combining unique numbers with cryptographically random numbers.
- 以这种方式生成的数字是否会以任何方式暴露给最终用户?如果不是,就没有必要用"shuffling"它们来混淆它们了。
此外,根据您使用的 SQLite API(针对您的编程语言),可能有一种方法可以编写自定义函数来将种子和 ROWID
转换为随机数唯一编号。然而,细节在很大程度上取决于特定的 SQLite API。 显示 Perl 示例。
如何使用良好的散列函数并将结果映射到 [1...max] 范围?
沿线(伪代码)。 sha1
已添加到 SQLite 3.17。
sha1(ROWID) % Max + 1
或使用任何外部 C 代码进行哈希(murmur、chacha、...),如图所示 here
我不确定您是否仍然遇到同样的问题,但我可能会为您提供解决方案。
你可以做的是使用基于移位寄存器的伪随机 M 序列生成器。您只需要对原始多项式进行足够高的阶数,而实际上不需要存储任何变量。
有关详细信息,您可以查看 wiki page
你需要编写的只是原始多项式移动方程,我已经在在线编辑器中检查过它应该很容易做到。我认为对您来说最简单的方法是使用 Binary base 并使用 PRBS 序列,并根据您将拥有的元素数量选择序列长度。例如,这是 2^15 = 32768
(PRBS15) 长度的实现,我从 wiki 页面获取的原始多项式(在那里你可以找到一直到 PRBS31 的原始多项式 2^31=2.1475e+09
)
基本上你需要做的是:
SELECT (((ROWID << 1) | (((ROWID >> 14) <> (ROWID >> 13)) & 1)) & 0x7fff)
这种方法的美妙之处在于,如果您采用周期长于 ROWID 最大值的 PRBS 序列,您将拥有唯一的随机索引。很简单的。 :)
如果您在搜索原始多项式方面需要帮助,您可以查看我的 github repo,它专门处理查找原始多项式和唯一 m 序列的问题。它目前是用 Matlab 编写的,但我计划在接下来的几天内用 python 编写它。
干杯!
是否有任何(简单的)随机生成函数可以在没有变量赋值的情况下工作?我阅读的大多数函数看起来像这样 current = next(current)
。但是目前我有一个限制(来自 SQLite)我根本不能使用任何变量。
有没有办法生成一个只有 n
(序列中的当前数字索引)和 seed
的数字序列(例如,从 1 到 max
)?
目前我正在使用这个:
cast(((1103515245 * Seed * ROWID + 12345) % 2147483648) / 2147483648.0 * Max as int) + 1
其中 max
为 47,ROWID
为 n
。然而,对于某些种子,重复率太高(47 个中有 3 个是唯一的)。
在我的要求中,重复是可以的,只要不是太多(<50%)即可。有没有更好的功能满足我的需求?
问题有sqlite标签,但任何language/pseudo-code都可以。
P.s:我曾尝试将 Linear congruential generators 与一些 a/c/m 三胞胎一起使用,并将 Seed * ROWID
用作 Seed
,但效果不佳,甚至更糟。
编辑:我目前使用这个,但我不知道它来自哪里。汇率看起来比我的好:
((((Seed * ROWID) % 79) * 53) % "Max") + 1
A linear congruential generator with appropriately-chosen parameters (a, c, 和模 m)将是一个 full-period 生成器,这样它在重复之前伪随机地循环遍历其周期中的每个整数。尽管您以前可能尝试过这个想法,但您是否考虑过m 等同于您的情况下的max
?有关此类生成器的参数选择列表,请参阅 L'Ecuyer, P., "Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure", Mathematics of Computation 68(225), January 1999.
请注意,在 SQLite 中实现此操作存在一些实际问题,特别是如果您的 SQLite 版本仅支持 32 位整数和 64 位 floating-point 数字(精度为 52 位)。也就是说,可能存在风险——
- 如果整数的中间乘法超过 32 位,则溢出,并且
- 如果中间乘法产生 greater-than-52 位数字,则精度损失。
此外,请考虑您创建随机数序列的原因:
- 这个顺序是不是故意设计成不可预测的?在这种情况下,仅线性同余生成器是不够的,您应该通过其他方式生成唯一标识符,例如 combining unique numbers with cryptographically random numbers.
- 以这种方式生成的数字是否会以任何方式暴露给最终用户?如果不是,就没有必要用"shuffling"它们来混淆它们了。
此外,根据您使用的 SQLite API(针对您的编程语言),可能有一种方法可以编写自定义函数来将种子和 ROWID
转换为随机数唯一编号。然而,细节在很大程度上取决于特定的 SQLite API。
如何使用良好的散列函数并将结果映射到 [1...max] 范围?
沿线(伪代码)。 sha1
已添加到 SQLite 3.17。
sha1(ROWID) % Max + 1
或使用任何外部 C 代码进行哈希(murmur、chacha、...),如图所示 here
我不确定您是否仍然遇到同样的问题,但我可能会为您提供解决方案。 你可以做的是使用基于移位寄存器的伪随机 M 序列生成器。您只需要对原始多项式进行足够高的阶数,而实际上不需要存储任何变量。 有关详细信息,您可以查看 wiki page
你需要编写的只是原始多项式移动方程,我已经在在线编辑器中检查过它应该很容易做到。我认为对您来说最简单的方法是使用 Binary base 并使用 PRBS 序列,并根据您将拥有的元素数量选择序列长度。例如,这是 2^15 = 32768
(PRBS15) 长度的实现,我从 wiki 页面获取的原始多项式(在那里你可以找到一直到 PRBS31 的原始多项式 2^31=2.1475e+09
)
基本上你需要做的是:
SELECT (((ROWID << 1) | (((ROWID >> 14) <> (ROWID >> 13)) & 1)) & 0x7fff)
这种方法的美妙之处在于,如果您采用周期长于 ROWID 最大值的 PRBS 序列,您将拥有唯一的随机索引。很简单的。 :)
如果您在搜索原始多项式方面需要帮助,您可以查看我的 github repo,它专门处理查找原始多项式和唯一 m 序列的问题。它目前是用 Matlab 编写的,但我计划在接下来的几天内用 python 编写它。
干杯!