【问题标题】:generating simple random number with time in c在c中随时间生成简单随机数
【发布时间】:2013-10-02 08:54:55
【问题描述】:

我正在使用这个功能:

int rand2(int lim)
{
        static long a = 1;  // could be made the seed value
        a = (a * 32719 + 3) % 32749;
        return ((a % lim) + 1);
}

要获得一堆随机数,它工作正常,但每次我启动这个函数时,我都会有相同的数字堆栈,所以我想使用 time() 系统函数每次都有不同的堆栈

p>
int rand3(int lim, int dat_time)
{
  static int a = dat_time; // could be made the seed value                                                       
  a = (a * 32719 + 3) % 32749;
  return ((a % lim) + 1);
}

然后我给我一次计算机的 time(),因为变量 a 是静态的

int             main()
{
  int           rd;
  time_t        timee;
  int           seed;

  timee = 0;
  timee = time(timee);
  seed = timee;
  while(42)
    {
      rd = rand3(52, seed);
      printf("%d\n", rd);
      getchar();
    }
}

然后我收到一条错误消息,说 dat_time 不是一个常数,但由于我有一次使用它,所以我不明白为什么

【问题讨论】:

标签: c random


【解决方案1】:

静态存储持续时间变量在任何代码开始运行之前进行初始化,并且必须使用可在编译时计算的表达式进行初始化。

这意味着不使用直到运行时才能确定的变量来初始化它们。如果你删除了static,错误就会消失,但是你每次调用它时都要重新播种随机数生成器。

您确实应该在请求第一个随机数之前初始化随机种子一次(如 C 标准库中的 srand()/rand()),然后使用您的随机函数循环遍历序列。这可以通过以下方式完成:

int rand4 (int numLimit) {
    static int randSeed, needsInit = 1;
    if (needsInit) {                      // This bit only done once.
        randSeed = time(0);
        needsInit = 0;
    }
    randSeed = (randSeed * 32719 + 3) % 32749;
    return (randSeed % numLimit) + 1;
}

srand()/rand() 中的typical implementation 大致如下:

// RAND_MAX assumed to be 32767.
static unsigned long int next = 1;
void srand(unsigned int seed) { next = seed; }
int rand(void) {
    next = next * 1103515245 + 12345;
    return (unsigned int)(next/65536) % 32768;
}

在其自己的源文件中,以便将next 种子隐藏在视图之外。这遵循了预期的行为,即在没有先调用srand() 的情况下调用rand() 与调用srand (1) 相同。


而且,根据您的评论,您需要进行一定次数的调用才能生成从 1 到 52 的所有数字,听起来您正在使用它来生成随机的一副牌。如果是这样的话,有一个比生成随机数并扔掉你已经看过的更好的方法。

随着剩余牌组的尺寸越来越小,该解决方案会迅速恶化。对于 O(1) 时间和空间解决方案,请使用 Fisher-Yates shuffle。

基本算法是使用一个未排序的列表,并简单地将最终元素与随机选择的元素交换,将列表大小减少一:

dim n[N]                  // gives n[0] through n[N-1]

for each i in 0..N-1:     // initialise them to their indexes
    n[i] = i              // (use i+1 for 1-10 instead of 0-9).

nsize = N                 // starting pool size
do N times:
    i = rnd(nsize)        // give a number between 0 and nsize-1
    print n[i]
    nsize = nsize - 1     // these two lines effectively remove the used number
    n[i] = n[nsize]

由此产生的数字是:

<------ n[] ------>
0 1 2 3 4 5 6 7 8 9  nsize  rnd(nsize)  output
-------------------  -----  ----------  ------
0 1 2 3 4 5 6 7 8 9     10           4       4
0 1 2 3 9 5 6 7 8        9           7       7
0 1 2 3 9 5 6 8          8           2       2
0 1 8 3 9 5 6            7           6       6
0 1 8 3 9 5              6           0       0
5 1 8 3 9                5           2       8
5 1 9 3                  4           1       1
5 3 9                    3           0       5
9 3                      2           1       3
9                        1           0       9

【讨论】:

  • 好的,看起来很棒,对于我需要的信息 50000000 在我之前的所有 52 个测试之前 ^^
  • 感谢您的链接,由于资源需求很少,我将继续使用我以前的功能
  • 没问题,@Saxtheowl,只是提供了一个选项。
【解决方案2】:

从int a = dat_time中去掉静态,将随机数的返回值作为下一次的种子。

int rand3(int lim, int dat_time)
{
  int a = dat_time; // could be made the seed value                                                       
  a = (a * 32719 + 3) % 32749;
  return ((a % lim) + 1);
}

int             main()
{
  int           rd;
  time_t        timee;
  int           seed;

  timee = 0;
  timee = time(timee);
  seed = timee;
  while(42)
  {
      rd = rand3(52, seed);
      printf("%d\n", rd);
      getchar();
      seed = rd;   // < Use the new random number as the seed for the next one
  }
}

【讨论】:

  • 是的,但是我的随机数栈每次都一样
  • 如果你使用返回值 rd 作为下一次调用的种子,你不会。但这不是你问的问题。
【解决方案3】:

如果您将种子传递给随机数生成器函数,那么您必须注意每次调用都更改种子,否则您将始终得到相同的数字。

相反,我建议您在创建两个函数时重用标准 srandrand 函数使用的模式:一个设置种子,另一个获取随机数。然后种子将成为全局变量,而不是函数内静态变量。


您当然可以使用单个函数,但是该函数必须能够更改种子。这可以通过引用传递“种子”/“状态”参数来完成:

int rand3(int lim, int *state)
{
    *state = (*state * 32719 + 3) % 32749;
    return ((*state % lim) + 1);
}

那么在调用函数的时候就得使用address-of操作符&amp;

int rng_state = time(NULL);  /* See the initial state (aka seeding) */

for (int i = 0; i < 10; ++i)
    printf("A random number: %d\n", rand3(52, &rng_state));

【讨论】:

    【解决方案4】:

    这应该可行,我写了一个::

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main ( void )
    {
      int r;
    
      srand ( (unsigned)time ( NULL ) );
      r = rand();
    
      printf ( "random number = %d\n", r );
    
      return 0;
    }
    

    但我建议,您可以从

    中删除静态关键字
    static int a = dat_time; // could be made the seed value
    

    【讨论】:

    • -1 不回答问题。 OP 在编写他/她自己的随机数生成器时需要帮助。他们不是在寻求标准库 rand() 函数的帮助。
    猜你喜欢
    • 2013-03-15
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 2015-07-19
    相关资源
    最近更新 更多