【问题标题】:How to improve this random number generator code in c++?如何在 C++ 中改进这个随机数生成器代码?
【发布时间】:2016-05-07 23:36:48
【问题描述】:

我是 C++ 学生,我正在创建一个随机数生成器。

事实上我应该说我的算法选择了一个定义范围内的数字。

我写这篇只是因为我的好奇心。

我不是在挑战现有的库函数。

在编写基于随机性的应用程序时,我总是使用库函数,但我再次声明,我只是出于好奇而想实现它。

我也想知道我的算法或方法是否有问题。 因为我在谷歌上搜索了 PRNG 的工作原理,并且在一些网站上他们说存在数学算法,并且预定义的数字序列和种子只是将指针设置在序列中的不同点,并且在一些间隔后序列会重复自身。

我的算法刚刚开始在可能值数组中来回移动,并且种子每次都以不同的值打破循环。我不认为这种方法是错误的。我得到了建议不同算法的答案,但他们没有解释我当前的算法有什么问题?

是的,我的种子有问题,因为它不精确,结果难以预测,如下所示:-

cout

运行四次的结果是74,93,56,79。

参见“递增顺序”的模式。

对于大范围的模式可以很容易地看到。我得到了关于获得好种子的答案,但也推荐了一种新算法(但没有说明原因?)。

另一种方法可能是随机打乱我的数组,每次都随机生成一个新序列。并且增加顺序的模式将会消失。任何重新排列的帮助也会很好。这是下面的代码。如果我的功能不可用请通知我。

谢谢你的期待。

int rn(int lowerlt, int upperlt)
{
    /* Over short ranges, results are satisfactory.
     * I want to make it effective for big ranges.
     */

    const int size = upperlt - lowerlt; // Constant size of the integer array.

    int ar[size]; // Array to store all possible values within defined range.
    int i, x, ret; // Variables to control loops and return value.
    long pointer = 0; //pointer variable. The one which breaks the main loop.


    // Loop to initialize the array with possible values..
    for (i=0, x=lowerlt; x <= upperlt; i++, x++)
        ar[i]=x;

    long seed = time(0);

    //Main loop . To find the random number.
    for (i=0; pointer <= seed; i++, pointer++)
    {
        ret = ar[i];
        if (i == size-1)
        {
            // Reverse loop.
            for (; i >= 0; i--)
            {
                ret=ar[i];
            }
        }
    }

    return ret;
}

【问题讨论】:

  • “主要问题”是编写 RNG 很难,没有什么特别推荐您采用的方法。这个问题的答案只包括建议另一种现有的算法,您也可以自己找到它,并获得更多好处。
  • @EJP 构建 RNG 很难与否,找到解决方案很重要。我知道库函数。我只是寻求一点帮助。我只是想知道不同的编程技术。我是新来的。
  • 所以按照我的建议去找一个。而不是从猜测开始。你会学到很多东西。
  • @EJP 是的,我会找到一个。这就是我来这里的原因。
  • PRNG 是一个非常困难的主题,如果你想写一个有竞争力的 w.r.t.现有的实现。因此,要么使用现有的(来自&lt;random&gt;),要么花费数年时间研究它们。或者编辑你的问题来解释你为什么要写一个。

标签: c++ c++11 shuffle random-seed


【解决方案1】:

警告:从您的帖子中,除了您的随机生成器算法之外,您的问题之一是获得一个好的种子值,所以我将解决这部分问题。

您可以使用/dev/random 来获取种子值。这将是一个很好的起点[并且本身就足够了],但从某些角度来看可能会被视为“作弊”。

所以,这里有一些“熵”的其他来源:

使用更高分辨率的时钟源:gettimeofdayclock_gettime(CLOCK_REALTIME,...) 将其称为“cur_time”。分别只使用微秒或纳秒部分,称之为“cur_nano”。请注意,cur_nano 通常是非常随机的。

做一个getpid(2)。这有一些不可预测的位,因为在调用之间其他程序正在启动,我们不知道有多少。

创建一个新的临时文件并获取文件的 inode 号 [然后删除它]。这会随着时间缓慢变化。每次调用都可能相同[或不同]

获取系统启动时系统时钟的高分辨率值,称之为“sysboot”。

获取“会话”开始时间的高分辨率值:当程序的父 shell 启动时,将其命名为“shell_start”。

如果您使用的是 Linux,您可以计算出 /proc/interrupts 的校验和,因为它总是在变化。对于其他系统,获取各种类型的中断数量的哈希值[应该可以从某种类型的系统调用中获得]。

现在,为以上所有内容创建一些哈希(例如):

dev_random * cur_nano * (cur_time - sysboot) * (cur_time - shell_start) *
getpid * inode_number * interrupt_count

这是一个简单的等式。您可以通过一些 XOR 和/或 sum 操作来增强它。进行试验,直到找到适合您的。

注意:这只会为您提供 PRNG 的种子值。您必须从其他东西(例如厄尔的线性算法)创建您的 PRNG

【讨论】:

    【解决方案2】:
    unsigned int Random::next() {
        s = (1664525 * s + 1013904223);
        return s;
    }
    

    's' 随着该函数的每次调用而增长。 正确的是

    unsigned int Random::next() {
       s = (1664525 * s + 1013904223) % xxxxxx;
       return s;
    }
    

    也许使用这个功能

    long long Factor = 279470273LL, Divisor = 4294967291LL;
    long long seed;
    next()
    {
        seed = (seed * Factor) % Divisor;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多