2010-04-14 260 views
6

我想为一个psudo随机数生成器生成一个好的随机种子。我想我会得到专家的意见。让我知道这是否是一种不好的做法,或者是否有更好的方法。C++为psudo随机数生成器生成一个很好的随机种子

#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() 
+0

别忘了掷骰子和异或与它;) – Andrey 2010-04-14 20:20:10

+2

如果你的过程运行的文件句柄,并无法打开'的/ dev/random'会发生什么? – 2010-04-14 20:21:16

回答

0

定义好。 :-)

很重要快速找到种子,或种子尽可能随机不管需要多长时间放在一起?

对于平衡 - 绝对不是最随意,绝对不是最快的......

  • 当它第一次调用,占用系统时间,以毫秒为单位。
  • 通过散列函数(如SHA-1)运行该函数。
  • 使用结果作为种子。

这应该给你一个大部分随机的160位,这是变化的10^50左右。散列运行需要一秒钟的时间,所以这不是闪电般的,但在过去对我来说是一个很好的平衡。

+0

我想为我的应用程序尽可能随机,但我也会对快速解决方案感兴趣。 – posop 2010-04-14 20:22:07

+3

@DeanJ哈希是多余的。直接播种系统时间。你试图用哈希完成的是(好的)伪随机数发生器已经*做了*(更好)。 – 2010-04-14 20:34:26

+0

Jon-Eric 100%正确;另一方面,我习惯于使用不好的随机数生成器,不能从坏的随机数生成器中分辨出好的,并且倾向于坚持(快速)矫枉过正。 – 2010-04-14 20:43:49

1

传统上,我们已经使用了第一或第二用户输入种子我们的值作为(抽动到毫秒范围)量所需的时间他们响应是相当变量。

5

从/ dev/random读取的代码看起来是错误的:你的C风格将你的字符缓冲区的地址转换为random_seed_a(这里用于C++转换的插件)并忽略你从/ dev/random尝试*reinterpret_cast<int*>(memblock)

/dev/random应该已经是一个很好的熵源了,所以如果它可用,不可能将该值与任何其他数据一起使用,直接用它作为种子,如果没有足够的数据在的/ dev /随机我只是回落的时间和使用本身,而不是什么异或运算它。

+1

根据我的研究,非确定性随机变量“dev/urandom”与非随机变量时间(0)相比较仍然是非确定性随机变量。 – posop 2010-04-14 23:13:52

2

良好的伪随机数生成器并不需要一个“好”的种子,任何种子(这不同于跑步跑步)效果同样好。

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

如果你的伪随机数发生器不好,即使选择一个“好”种子也无济于事。如果可以,请替换它。

建议:Mersenne twister是一个相当不错重视。即使在最有限的系统上也能运行的前驱物。

+3

根据目的,伪随机数发生器可能需要一个不可预测的种子。有一个在线扑克游戏把时间花费在可能是体面的PRNG上,这意味着通过观察一些卡片,可以找出PRNG开始的位置,从而了解整个套牌。 – 2010-04-14 21:07:05

+1

如果用户无法预测随机数字序列对用户来说非常重要,那么您需要密码安全的生成器,而不是伪随机生成器。 (如果你使用伪随机发生器进行真钱赌博,你会很疯狂。) – 2010-04-14 21:15:51

+0

仅仅在FYI和Mersenne twister中,你必须观察624张连续牌(12副牌),然后才能知道所有将来的牌。 – 2010-04-14 21:30:59

0

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

1

“好”的发电机,“坏发电机”并不意味着什么。 “任何考虑产生随机数字的算术方法的人当然都处于犯罪状态。” - 约翰冯诺依曼。每个这样的生成器都只是一个确定性算法。它的重要的是具有足够的熵的初始状态(种子)。 根据你的需要,你应该测试你的发电机质量。蒙特卡罗方法是伪随机数发生器的一个非常好的估计器。

2

好的,这是我在考虑你的输入后所做的改变。感谢您的一切顺便!

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()