一尘不染

伪随机分布,可保证值序列的所有可能排列-C ++

algorithm

随机问题。

我正在尝试创建一个程序,该程序将生成伪随机分布。我正在尝试找到适合我需要的正确的伪随机算法。这些是我的担忧:

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。并且它仅对单个整数是可逆的,对于序列是不可逆的(因为不是所有序列都可以由它产生)。我正在使用Boost
multiprecision在C ++中工作。

有人可以给我关于生成满足这些要求的随机分布的任何建议,或者仅仅是一类值得为此目的进行研究的算法,我将不胜感激。预先感谢您考虑我的问题。

-—更新----

由于多个评论者都集中在所讨论数字的大小上,我只是想表明我已经意识到使用此类集合所带来的实际问题,但是在提出这个问题时,我只对解决问题的理论或概念方法感兴趣。问题-
例如,想象一下使用更小的整数集(例如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的值一起使用将打印出您需要找到反值以及反值的欧几里得方程:

    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;}

我希望这对将来冒险的人有所帮助。


阅读 304

收藏
2020-07-28

共1个答案

一尘不染

好的,我不确定是否有一个一般性的答案,所以我将专注于具有例如64位内部状态/种子,产生64位输出并具有2 ^
64-1周期的随机数生成器。我特别要看一下线性同余生成器(又名LCG),其形式为

next = (a * prev + c) mod m

在哪里am彼此互质

所以:

1)检查

2)检查

3)检查(当然,要保留64位空间)

4)检查(同样,我相信除了0以外,但64位的每个排列都是从LCG的某些种子开始输出的)

5)检查。LCG是可逆的,即可以

prev = (next - c) * a_inv mod m

其中a_inv可以从计算am使用Euclid算法

好吧,如果您觉得还可以,则可以尝试在15546位空间中实现LCG

更新

快速搜索在此处显示可逆的LCG讨论/代码

2020-07-28