c - 无法理解此随机数生成器代码

标签 c random

我正在做一个类项目,我正在使用教科书中的代码在我的代码中生成一个随机数。但是,每次我运行代码时,无论如何都会得到相同的输出,这让我很困惑,所以我猜我实际上并不了解随机数生成器的工作原理。代码在下面 - 它带有说明,但我不确定每次运行代码时我应该怎么做才能生成随机结果?

/* Prime modulus multiplicative linear congruential generator
   Z[i] = (630360016 * Z[i-1]) (mod(pow(2,31) - 1)), based on Marse and Roberts'
   portable FORTRAN random-number generator UNIRAN.  Multiple (100) streams are
   supported, with seeds spaced 100,000 apart.  Throughout, input argument
   "stream" must be an int giving the desired stream number.  The header file
   lcgrand.h must be included in the calling program (#include "lcgrand.h")
   before using these functions.

   Usage: (Three functions)

   1. To obtain the next U(0,1) random number from stream "stream," execute
          u = lcgrand(stream);
      where lcgrand is a float function.  The float variable u will contain the
      next random number.

   2. To set the seed for stream "stream" to a desired value zset, execute
          lcgrandst(zset, stream);
      where lcgrandst is a void function and zset must be a long set to the
      desired seed, a number between 1 and 2147483646 (inclusive).  Default
      seeds for all 100 streams are given in the code.

   3. To get the current (most recently used) integer in the sequence being
      generated for stream "stream" into the long variable zget, execute
          zget = lcgrandgt(stream);
      where lcgrandgt is a long function. */

/* Define the constants. */

#define MODLUS 2147483647
#define MULT1       24112
#define MULT2       26143

/* Set the default seeds for all 100 streams. */

static long zrng[] =
{         1,
 1973272912, 281629770,  20006270,1280689831,2096730329,1933576050,
  913566091, 246780520,1363774876, 604901985,1511192140,1259851944,
  824064364, 150493284, 242708531,  75253171,1964472944,1202299975,
  233217322,1911216000, 726370533, 403498145, 993232223,1103205531,
  762430696,1922803170,1385516923,  76271663, 413682397, 726466604,
  336157058,1432650381,1120463904, 595778810, 877722890,1046574445,
   68911991,2088367019, 748545416, 622401386,2122378830, 640690903,
 1774806513,2132545692,2079249579,  78130110, 852776735,1187867272,
 1351423507,1645973084,1997049139, 922510944,2045512870, 898585771,
  243649545,1004818771, 773686062, 403188473, 372279877,1901633463,
  498067494,2087759558, 493157915, 597104727,1530940798,1814496276,
  536444882,1663153658, 855503735,  67784357,1432404475, 619691088,
  119025595, 880802310, 176192644,1116780070, 277854671,1366580350,
 1142483975,2026948561,1053920743, 786262391,1792203830,1494667770,
 1923011392,1433700034,1244184613,1147297105, 539712780,1545929719,
  190641742,1645390429, 264907697, 620389253,1502074852, 927711160,
  364849192,2049576050, 638580085, 547070247 };

/* Generate the next random number. */

float lcgrand(int stream)
{
    long zi, lowprd, hi31;

    zi     = zrng[stream];
    lowprd = (zi & 65535) * MULT1;
    hi31   = (zi >> 16) * MULT1 + (lowprd >> 16);
    zi     = ((lowprd & 65535) - MODLUS) +
             ((hi31 & 32767) << 16) + (hi31 >> 15);
    if (zi < 0) zi += MODLUS;
    lowprd = (zi & 65535) * MULT2;
    hi31   = (zi >> 16) * MULT2 + (lowprd >> 16);
    zi     = ((lowprd & 65535) - MODLUS) +
             ((hi31 & 32767) << 16) + (hi31 >> 15);
    if (zi < 0) zi += MODLUS;
    zrng[stream] = zi;
    return (zi >> 7 | 1) / 16777216.0;
}


void lcgrandst (long zset, int stream) /* Set the current zrng for stream
                                          "stream" to zset. */
{
    zrng[stream] = zset;
}


long lcgrandgt (int stream) /* Return the current zrng for stream "stream". */
{
    return zrng[stream];
}

编辑:我忘了实际包含运行这些函数的代码,它是这样的:

float Expon(float mean)  /* Exponential variate generation function. */
{
    /* Return an exponential random variate with mean "mean". */
    return -mean * log(lcgrand(1));
}

根据我有限的理解,我认为我的问题是由 lcgrand(1) 引起的,但我不完全确定。

最佳答案

计算机通常无法生成真正的随机数,因为它们被设计为确定性地运行,这基本上与随机相反。由于程序控制着所有的输入,而且程序不会改变,所以输出不可能是真正随机的。这就是为什么许多计算机生成的随机数被称为伪随机而不是随机数的原因。

然而,尽管生成的数字不可能是真正随机的,但您可以通过引入一些每次运行程序时都会发生变化的变量来降低它们的可预测性,并在每次运行程序时获得不同的序列。该变量称为“种子”。许多程序将使用来自计算机时钟的值或来自其他不可预测的值来播种它们的随机数生成器,例如来自用户提供的鼠标移动的一系列鼠标坐标,以及可能是鼠标移动之间的时间.

查看您提供的代码,请注意种子都列为“默认种子”,这意味着如果您不希望该流每次都提供相同的结果,您应该覆盖特定流的种子运行程序的时间。

您可能认为这是很多代码来提供可以直接从鼠标或时钟中简单检索的值。所有这些代码的目的是让某人尽可能难以预测序列中的下一个数字将给出过去的结果采样(毕竟任何具有相同随机数生成器代码的人都可以尝试匹配的一部分他们的序列与你的序列来预测接下来会发生什么,这是随机数生成器通常试图阻止的)。因此,代码必须非常重要,以减少其他人使用它来预测下一个数字的可能性。

在运行时使用(由时钟或鼠标)生成的种子是防止值可预测的一种方法。但通常持续提供随机种子是不切实际的。而且由于随机种子有时可以基于非随机源(如时钟),您最终可能仅凭这些值就具有一定的可预测性。因此,由于大多数种子数据来源并不是真正随机的,因此您必须让程序花费一些时间使其尽可能随机和不可预测。通过组合不同的种子值根据大量难以复制的输入生成数字的代码,您可以快速获得非常接近真正随机数的结果。

由于这是一个类,我将留给您阅读关于如何设置种子的使用点 2 的评论。

关于c - 无法理解此随机数生成器代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41088673/

相关文章:

创建二维数组并设置值

c - 为什么 (1.1-1.0)*10 不是 1.0?

android - Catch Android 随机崩溃技巧

arrays - 以 30% 的概率动态分配和初始化新对象

python - 如何创建空词典列表并填充后记?

ruby - 生成随机数,但有异常(exception)

c - 如何在C中打印毫秒?

c - 如何为结构中的函数指针成员赋值

c - 搜索数组不提供适当的输出

c - 如何在 C 语言中使用 ISAAC