随机问题。
我正在尝试创建一个会生成伪随机分布的程序。我正在尝试为我的需要找到正确的伪随机算法。这些是我的担忧:
1)每次使用时我都需要一个输入来生成相同的输出。
2)它需要足够随机,以使查看输入 1 的输出的人看不到它与输入 2 的输出(等等)之间没有任何联系,但不需要它是加密安全的或真正随机的。
3)它的输出应该是一个介于 0 和 (29^3200)-1 之间的数字,该范围内的每个可能的整数都是一个可能且同样(或接近)可能的输出。
4)我希望能够保证 410 个输出序列的每个可能排列也是连续输入的潜在输出。换句话说,0 到 (29^3200)-1 之间的 410 个整数的所有可能分组应该是顺序输入的潜在输出。
5)我希望函数是可逆的,这样我就可以取一个整数或一系列整数,并说出哪个输入或一系列输入会产生该结果。
到目前为止我开发的方法是通过一个简单的 halson 序列运行输入:
boost::multiprecision::mpz_int denominator = 1;
boost::multiprecision::mpz_int numerator = 0;
while (input>0) {
denominator *=3;
numerator = numerator * 3 + (input%3);
input = input/3;
}
并将结果乘以 29^3200。它满足要求 1-3,但不满足要求 4。而且它只对单个整数可逆,而不是对数列可逆(因为不是所有数列都可以由它产生)。我在 C++ 中工作,使用 boost 多精度。
任何人可以给我的关于生成满足这些要求的随机分布的方法的任何建议,或者只是为此目的值得研究的一类算法,将不胜感激。提前感谢您考虑我的问题。
- - 更新 - -
由于多个评论者都关注相关数字的大小,我只是想明确表示,我认识到使用这些集合会带来的实际问题,但在提出这个问题时,我只对理论或概念方法感兴趣问题 - 例如,想象使用更小的整数集(如 0 到 99)以及 10 个输出序列集的排列。您将如何设计一种算法来满足这五个条件 - 1)输入是确定性的,2)出现随机(至少对人眼而言),3)范围内的每个整数都是可能的输出,4)不仅是所有值,而且值序列的所有排列都是可能的输出,5)函数是可逆的。
---第二次更新---
非常感谢@Severin Pappadeux,我能够反转 lcg。我想我会添加一些关于我所做的事情,以希望将来让任何人更容易看到这一点。首先,这些是反模函数的极好资源:
https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/modular-inverses
https://www.khanacademy.org/computer-programming/discrete-reciprocal-mod-m/6253215254052864
如果你采用等式 next=ax+c%m,使用下面的代码和你的 a 和 m 值将打印出你需要找到 ainverse 的欧几里得方程,以及 ainverse 的值:
int qarray[12];
qarray[0]=0;
qarray[1]=1;
int i =2;
int reset = m;
while (m % a >0) {
int remainder=m%a;
int quotient=m/a;
std::cout << m << " = " << quotient << "*" << a << " + " << remainder << "\n";
qarray[i] =qarray[i-2]-(qarray[i-1]*quotient);
m=a;
a=remainder;
i++;
}
if (qarray[i-1]<0) {qarray[i-1]+=reset;}
std::cout << qarray[i-1] << "\n";
我花了一段时间才弄清楚的另一件事是,如果你得到一个否定的结果,你应该给它加上 m。您应该在新方程中添加一个类似的项:
prev = (ainverse(next-c))%m;
if (prev<0) {prev+=m;}
我希望这对将来在这条路上冒险的人有所帮助。