【问题标题】:trying to find a fully-random number generator试图找到一个完全随机的数字生成器
【发布时间】:2012-12-05 23:38:37
【问题描述】:

我在 C 中工作,我正在(拼命地)尝试制作一个随机生成器,它不仅可以生成 每次运行生成器时都有一个不同的数字,但每次运行程序时也有不同的序列。我测试了我在网上找到的几乎所有东西。我找到了 2 种制作好的随机发生器的好方法。 第一个是每次都使用不同的种子。但这意味着我每次都必须使用不同的随机种子,这是我一开始没有解决的问题。这是我现在正在尝试的,但这不是真的随心所欲:

int myrand(int random_seed){
  random_seed = random_seed * 1103515245 +12345;   
  return (unsigned int)(random_seed / 65536) % 32768; 
                           }

每次我调用该函数时,我都会将种子增加 1。

第二种方法是使用时间。时间变化,这是随机性。我也尝试了很多方法来实现这一点。我最近的尝试是在这里: Compiler error-Possible IDE error"undefined reference to gettimeofday error" 但我无法使用 gettimeofday 函数,因为我在 Windows 中工作。同样在那个问题中我没有得到任何答案。

谁能帮助我如何在 Windows 中使用 C 实现随机生成器(可能使用时间)?或者我应该使用 Unix 吗?

【问题讨论】:

  • srand() 有问题吗?你可以像这样播种:srand( time(NULL) );
  • 我也尝试过 srand(time(NULL)) 但我不得不延迟以等待时间更改。原因是我想一次生成大量随机数并且我不想等待 2 分钟让程序生成它们。我也尝试使用毫秒但没有成功。也许毫秒是答案,但我无法正确实施,问题是我正在使用 Windows .
  • @Dchris:在程序开始时以 一次 的时间为您的伪随机数生成器 (PRNG) 播种。然后,您可能必须确保每秒运行程序不超过一次(引入毫秒会对此有所帮助),但每次从 PRNG 中读取数字时,您不必等待一秒钟。跨度>
  • @SteveJessop:我希望这会奏效!

标签: c windows unix random time


【解决方案1】:

用良好的熵源为您的 RNG 播种。

在 unix 下,使用 /dev/random。

在 windows 下,使用 CryptoAPI - Windows equivalent of /dev/random

【讨论】:

  • 这仅用于重要的随机性。从 /dev/random 读取将耗尽系统的熵,当它最终为空时将导致阻塞,直到系统收集到更多的熵。当然,OP 没有说明他试图解决的问题是否与安全相关。我怀疑不是。
  • 更改为注意您可以通过这种方式为 rng 播种。
  • 在 C++11 上,您可以使用 std::random_device,它可能会使用系统上真正随机数据的任何来源。
【解决方案2】:

你要的不是随机数生成器,而是如何使用已经包含在C标准库中的随机数生成器。

您需要做的就是在程序启动时一次播种:

srand(time(NULL));

就是这样。它是可移植的,每次运行程序时都会为您提供不同的序列,因为距离您上次运行它至少已经过去了一秒钟。

以后再播也没坏处,但也没有意义。

【讨论】:

  • 补种不能掉以轻心。根据 PRNG 算法,可能需要重新播种以增加熵,但肯定有正确和错误的重新播种方法和基于不良重新播种的密码攻击。正如您所说,为简单的 PRNG 用例重新播种通常是不必要的。例如,MT 算法可以在重复之前生成惊人的 2^19937−1 个数字。其他的在骑车前最好到 2^32 个数字。
【解决方案3】:

C 标准库有头文件 time.h(或 ctime,如果你使用 C++)(reference)。那里的功能将在 Windows 和 Unix 中得到支持。

我会推荐 time() 或 clock() 作为随机数生成器的种子。

获得完全随机输入的另一种方法是使用鼠标位置或其他受外部影响的事物。

【讨论】:

    【解决方案4】:

    实现 prng 的方法有很多,但不幸的是,它们都不是真正的随机数生成器。 time(NULL) 是一个好方法,但我使用的是“blum blum shub”。它生成一位随机数

    【讨论】:

      【解决方案5】:

      由于您明确要求 Windows 解决方案,我建议避免将 time(NULL)clock() 作为 srand() 的种子,因为它们的粒度非常有限 (ms)。相反,您可以使用性能计数器的结果:

      LARGE_INTEGER PerformanceCount;
      QueryPerformanceCounter(&PerformanceCount);
      srand(PerformanceCount.LowPart);
      

      QueryPerformanceCounter()的频率增加率可以通过调用QueryPerformanceFrequency()获得。这通常至少增加 1 MHz,有时甚至增加到 GHz 范围。因此,它为种子提供了一个快速变化的来源。

      编辑:从您的earlier question 了解到,gettimeofday() 类似的实现不会提供精细的粒度。它可能会在其参数中显示单词tv_usec,但在 WIndows 上它不会像在 Linux 系统上那样提供微秒粒度。

      【讨论】:

        【解决方案6】:

        引用:

        to make a random generator that not only generates a different number every time i run the generator

        随机的定义不包括该概念。相反,这个想法是你有平等的机会选择任何数字,而不管之前选择的数字是多少。这意味着理论上可以选择两次相同的数字。

        如果您正在处理一副牌,那么这符合您的不重复标准。使用套牌处理方法意味着跟踪“使用过的”数字。

        您还应该知道 PNRG(伪随机数生成器)是循环的(周期性的)。在您生成数字(通常是一个大数字)之后,您重新开始并准确地重复数字的名称序列。 UNIX rand() 函数在 [0, {RAND_MAX}] 范围内生成整数整数,周期为 2^32

        真的考虑阅读这个简短的页面:

        见:http://pubs.opengroup.org/onlinepubs/009695399/functions/rand.html

        【讨论】:

          猜你喜欢
          • 2023-01-03
          • 1970-01-01
          • 2011-09-18
          • 2022-11-21
          • 2012-05-17
          • 2016-10-08
          • 2013-11-24
          • 1970-01-01
          • 2014-11-26
          相关资源
          最近更新 更多