如何编写两个函数来生成支持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
答案 0 :(得分:5)
您可以使用伪随机函数(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的一个子集,周期非常大,差别无关紧要。)
答案 1 :(得分:3)
一些linear congruential generators(常见但不太好的PRNG)是可逆的。
他们按next = (a * previous + c) mod m
工作。如果a
有modular multiplicative inverse mod m
,那就是可逆的。通常情况如此,因为m
通常是2的幂,而a
通常是奇数。
例如,对于&#34; MSVC&#34;来自第一个链接的表中的参数:
相反的是:
previous = (current - 2531011) * 0xb9b33155;
选择使其类型为2 32 的类型。
答案 2 :(得分:2)
假设您有一个由
定义的线性同余序列S
S[0] = seed
S[i] = (p * S[i-1] + k) % m
对于某些p
,m
,k
,gcd(p, m) == 1
。然后,您可以找到q
(p * q) % m == 1
和计算:
S[i-1] = (q * (S[i] - k)) % m
换句话说:如果您选择合适的p
并预先计算q
,您可以在O(1)
时间内以任意顺序遍历您的序列。
答案 3 :(得分:2)
生成可索引伪随机序列的一种相当简单的方法 - 即,看起来是随机的,但可以在任一方向上遍历的序列 - 是选择一些(相当好的)加密算法和固定的加密密钥,然后定义:
sequence(i): encrypt(i, known_key)
您不需要知道i
的价值,因为您可以从数字中解密它:
next(r): encrypt(decrypt(r, known_key) + 1)
prev(r): encrypt(decrypt(r, known_key) - 1)
因此,i
不必是一个小整数;因为你需要做的唯一算术是用小整数加法和减法,所以bignum实现是微不足道的。因此,如果您需要128位伪随机数,可以将第一个i
设置为从/dev/random
中提取的128位随机数。
您必须将i
的整个值保留在静态存储中,并且伪随机数的周期不能大于i
的范围。但是,对于此问题的任何解决方案都是如此:由于next()
和prev()
运算符必须是函数,因此每个值都有唯一的后继函数和前任函数,因此只能在价值循环。这与梅森捻线机完全不同,例如,其周期远大于2 32 。
答案 4 :(得分:0)
我认为你所要求的是确定性的随机数发生器。这没有意义,因为如果它是确定性的,那就不是随机的。唯一的解决方案是生成一个随机数列表,然后在此列表中前后移动。
PS!我知道所有软件PRNG-s都是确定性的。您当然可以使用它来创建您需要的功能,但不要欺骗自己,它与随机性无关。如果您的软件设计需要具有确定性的PRNG,那么您可以完全跳过PRNG部分。