【问题标题】:c++ generate a good random seed for psudo random number generatorsc++为伪随机数生成器生成一个好的随机种子
【发布时间】:2011-02-08 02:27:45
【问题描述】:

我正在尝试为伪随机数生成器生成一个好的随机种子。我想我会得到专家的意见。让我知道这是一种不好的方法还是有更好的方法。

#include <iostream>
#include <cstdlib>
#include <fstream>
#include <ctime>

unsigned int good_seed()
{
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/random", std::ios::binary);
    if (file.is_open())
    {
        char * memblock;
        int size = sizeof(int);
        memblock = new char [size];
        file.read (memblock, size);
        file.close();
        random_seed_a = int(memblock);
        delete[] memblock;
    }// end if
    else
    {
        random_seed_a = 0;
    }
    random_seed_b = std::time(0);
    random_seed = random_seed_a xor random_seed_b;
    return random_seed;
} // end good_seed()

【问题讨论】:

  • 别忘了掷骰子和异或;)
  • 如果你的进程用完了文件句柄并且无法打开/dev/random会发生什么?

标签: c++ random random-seed


【解决方案1】:

从 /dev/random 读取的代码似乎是错误的:您使用 C 风格将字符缓冲区的地址转换为 random_seed_a(此处插入 C++ 转换)并忽略您实际从 /dev/random 读取的任何内容(尝试*reinterpret_cast&lt;int*&gt;(memblock).

/dev/random 应该已经是一个很好的熵源,所以如果它可用,就不可能用任何其他数据污染值,直接将其用作种子。如果 /dev/random 中没有足够的数据,我会退回到时间并单独使用它,而不是用某些东西来异或。

【讨论】:

  • 根据我的研究,非确定性随机变量“dev/urandom”与非随机变量 time(0) 异或仍将是非确定性随机变量。
【解决方案2】:

好的伪随机数生成器不需要“好的”种子,任何种子(每次运行都不同)都可以正常工作。

直接使用系统时间很好(并且很常见)。使用/dev/random 也可以。

如果您的伪随机数生成器不好,即使选择“好”的种子也无济于事。如果可以,请更换它。

建议:Mersenne twister 很受好评。 Here's 可以在最有限的系统上运行的先驱。

【讨论】:

  • 根据目的,伪随机数生成器可能需要不可预测的种子。有一个在线扑克游戏将时间投入到可能是不错的 PRNG 中,这意味着可以通过观察一些牌来找出 PRNG 从哪里开始,从而了解整个牌组。
  • 如果用户无法预测随机数序列对用户来说根本很重要,那么您需要一个加密安全的生成器,而不是伪随机生成器。 (如果您将真钱赌博建立在伪随机生成器上,那您就疯了。)
  • 仅供参考,使用 Mersenne twister,您必须观察 624 连续牌(12 副牌)才能知道所有未来牌。
  • 是的。为了给予扑克网站应有的荣誉,他们并没有赌自己的钱,尽管我怀疑他们在消息传出后就失去了生意。
【解决方案3】:

好的,这是我在考虑您的意见后所做的更改。顺便感谢您所做的一切!

unsigned int good_seed()
{
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/urandom", std::ios::binary);
    if (file.is_open())
    {
        char * memblock;
        int size = sizeof(int);
        memblock = new char [size];
        file.read (memblock, size);
        file.close();
        random_seed_a = *reinterpret_cast<int*>(memblock);
        delete[] memblock;
    }// end if
    else
    {
        random_seed_a = 0;
    }
    random_seed_b = std::time(0);
    random_seed = random_seed_a xor random_seed_b;
    std::cout << "random_seed_a = " << random_seed_a << std::endl;
    std::cout << "random_seed_b = " << random_seed_b << std::endl;
    std::cout << " random_seed =  " << random_seed << std::endl;
    return random_seed;
} // end good_seed()

【讨论】:

    【解决方案4】:

    传统上,我们使用第一个或第二个用户输入来播种我们的值,因为它们响应所需的时间(抽动到毫秒范围)是非常可变的。

    【讨论】:

      【解决方案5】:

      也许你应该更喜欢/dev/urandom/ 而不是/dev/random。如果没有足够的可用熵,后者会在 Linux 上阻塞,如果程序在没有用户交互的机器上运行,则很容易发生这种情况。如果您无法打开/dev/urandom,您可以抛出异常而不是使用回退。

      【讨论】:

        【解决方案6】:

        “好的”生成器,“坏的生成器”没有任何意义。 “任何考虑产生随机数字的算术方法的人当然都处于犯罪状态。” ——约翰·冯·诺依曼。 每个这样的生成器都只是一个确定性算法。拥有能够带来足够熵的初始状态(种子)非常非常重要。 根据您的需要,您应该测试您的发电机质量。蒙特卡洛方法是一种很好的伪随机数发生器估计方法。

        【讨论】:

          【解决方案7】:

          定义好。 :-)

          快速找到种子重要吗,还是不管需要多长时间,种子都尽可能随机?

          为了平衡 - 绝对不是最随机的,绝对不是最快的......

          • 首次调用时,获取系统时间,以毫秒为单位。
          • 通过哈希函数(如 SHA-1)运行它。
          • 将结果用作种子。

          这应该给你一个主要是随机的 160 位,这是 10^50 左右的可变性。哈希将需要一秒钟的时间来运行,所以这不是闪电般的快,但在过去对我来说是一个很好的平衡。

          【讨论】:

          • 我希望我的应用程序尽可能随机,但我也对快速解决方案感兴趣。
          • @DeanJ 哈希是多余的。直接用系统时间播种。你试图用哈希完成的是(一个好的)伪随机数生成器已经做了(更好)。
          • 乔恩-埃里克是 100% 正确的;另一方面,我习惯于使用糟糕的随机数生成器,无法区分好与坏,并且倾向于坚持(快速)矫枉过正。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-03
          • 2021-05-15
          • 2015-08-07
          相关资源
          最近更新 更多