Algorithm 使用下一个和上一个支持生成随机数?

Algorithm 使用下一个和上一个支持生成随机数?,algorithm,random,Algorithm,Random,如何编写两个函数来生成支持next和previous的随机数 我的意思是如何编写两个函数:next_number和previous_number,next_number函数生成一个新的随机数,previous_number函数生成先前生成的随机数 例如: int next_number() { // ...? } int previous_number() { // ...? } int num; // Forward random number generating. //

如何编写两个函数来生成支持next和previous的随机数

我的意思是如何编写两个函数:next_number和previous_number,next_number函数生成一个新的随机数,previous_number函数生成先前生成的随机数

例如:

int next_number()
{
   // ...?
}

int previous_number()
{
   // ...?
}

int num;

// Forward random number generating.
// ---> 54, 86, 32, 46, 17
num = next_number(); // num = 54
num = next_number(); // num = 86
num = next_number(); // num = 32
num = next_number(); // num = 46
num = next_number(); // num = 17

// Backward random number generating.
// <--- 17, 46, 32, 86, 54
num = previous_number(); // num = 46
num = previous_number(); // num = 32
num = previous_number(); // num = 86
num = previous_number(); // num = 54

您可以使用伪随机函数PRF轻松实现这一点

这些函数接受一个键和一个值,并基于它们输出一个伪随机数。您可以从/dev/random中选择一个键,该键在程序运行时保持不变,然后向函数提供一个整数,该整数可以递增前进,也可以递减后退

下面是一个伪代码示例:

initialize():
    Key = sufficiently many bytes from /dev/random
    N = 0

next_number():
    N = N + 1
    return my_prf(Key, N)

previous_number():
    N = N - 1
    return my_prf(Key, N)
在大多数密码库中都可以找到强伪随机函数。正如rici所指出的,您也可以使用任何加密函数加密函数是伪随机排列,是PRF的子集,周期如此之大以至于差异无关紧要。

一些常见但不是很好的PRNG是可逆的

它们通过next=a*previous+c mod m工作。如果a有一个mod m,这是可逆的。通常是这样,因为m通常是2的幂,a通常是奇数

例如,对于第一个链接表中的MSVC参数:

m=232 a=214013 c=2531011 反之亦然:

previous = (current - 2531011) * 0xb9b33155;

选择了使其以232模工作的类型。

我认为您需要的是确定性的随机数生成器。这是没有意义的,因为如果它是确定性的,它就不是随机的。唯一的解决方案是生成一个随机数列表,然后在此列表中后退和前进


PS!我知道基本上所有的软件PRNG-s都是确定性的。当然,您可以使用它来创建所需的功能,但不要欺骗自己,它与随机性无关。如果您的软件设计需要具有确定性的PRNG,那么您可能完全可以跳过PRNG部分。

假设您有一个由

S[0] = seed
S[i] = (p * S[i-1] + k) % m
对于一些p,m,k,使得gcdp,m==1。然后您可以找到q,使得p*q%m==1并计算:

S[i-1] = (q * (S[i] - k)) % m

换句话说:如果你选择合适的p并预计算q,你可以在O1时间内以任意顺序遍历序列。

一种生成可索引伪随机序列的相当简单的方法-即,看起来随机的序列,但可以在任意方向上进行遍历-就是选择一些相当好的加密算法和固定的加密密钥,然后定义:

sequence(i): encrypt(i, known_key)
您不需要知道i的值,因为您可以从数字中解密i:

next(r): encrypt(decrypt(r, known_key) + 1)

prev(r): encrypt(decrypt(r, known_key) - 1)
因此,我不必是一个小整数;由于您需要对其执行的唯一算术是小整数的加减运算,因此bignum实现非常简单。因此,如果需要128位伪随机数,可以将第一个i设置为从/dev/random中提取的128位随机数


必须将i的整个值保存在静态存储中,伪随机数的周期不能大于i的范围。不过,对于这个问题的任何解决方案都是如此:因为next和prev运算符必须是函数,所以每个值都有一个唯一的后继和前导,因此在值循环中只能出现一次。这与Mersenne twister截然不同,例如,Mersenne twister的周期比232大得多。

难道你不能将目前为止生成的所有数字都存储在一个列表中吗?如果你只需要一个有限的N个数字序列,那么就将整数1..N随机洗牌,并存储洗牌后的集合。在你的示例中,如果你第五次拨打之前的号码会发生什么?@mbeckish:一个新的随机号码:我想你需要定义一下,随机对你意味着什么。它是不是意味着不连续,还是意味着尽可能少的确定性,就像我所说的伪随机。这是PRF中的P。我很确定你实际上是在扼杀R部分:@harold伪随机算法,在每次调用之前播种,如果不经常重新播种,它们可能会通过测试。@Theotherguy可能是为了一个安全的伪随机算法,但我知道一个事实,例如微软的兰德公司(rand)的种子与生成的下一个随机数之间存在高度相关性的问题。用递增的数字重新播种一点也不是随机的。@ErkiA如果只播种一次,情况也是如此。PRNG的输入总是确定性的。所有PRNG都是确定性的。OP要求一个伪随机序列,其逆也是确定性的,这将其循环周期限制为可能的随机值的数量。