【问题标题】:rand() is not returning random valuesrand() 不返回随机值
【发布时间】:2012-04-21 12:46:38
【问题描述】:

这是一个生成随机厄米特矩阵hermitian matrix的小代码。

我在每次调用 rand() 之前调用了 srand()。但输出中仍然没有随机性。

我使用了 c99 的复杂数据类型特性来创建一个厄米矩阵。我不确定我错在哪里:(

#include <stdio.h>
#include <math.h>
#include <complex.h>
#include <stdlib.h>
#include <time.h>

#define MATSIZE 5
#define RAND_RANGE 100

double complex mat[MATSIZE][MATSIZE];

void gen_mat()
{
  int i =0,j;
  int real;
  int img;
  for( ;i < MATSIZE; i++)
  {
    srand(time(NULL));
    real = rand()%RAND_RANGE + 1;
    srand(time(NULL));
    img = rand()%RAND_RANGE + 1;
    for(j = MATSIZE; j != i ; j--) 
    { 
       mat[i][j] = real + img * I;
       mat[j][i] = conj(mat[i][j]);
    }
    srand(time(NULL));
    if(i == j)
      mat[i][i] = rand()%RAND_RANGE + 0*I;
  }
}

void print_mat()
{
  int i,j;
  for(i = 0; i < MATSIZE; i++)
  {
    for(j = 0; j < MATSIZE; j++)
    {
      printf("%f + %f *i", creal(mat[i][j]), cimag(mat[i][j]));
      printf("    ");
    }
    puts("\n");
  }
}

int main()
{
  gen_mat();
  print_mat();
  return 0;
}

样本输出

[aft@centos-c physics-numaric]$ ./a.out 
66.000000 + 0.000000 *i    67.000000 + 67.000000 *i    67.000000 + 67.000000 *i             67.000000 + 67.000000 *i    67.000000 + 67.000000 *i    

67.000000 + -67.000000 *i    66.000000 + 0.000000 *i    67.000000 + 67.000000 *i      67.000000 + 67.000000 *i    67.000000 + 67.000000 *i    

67.000000 + 67.000000 *i    67.000000 + -67.000000 *i    66.000000 + 0.000000 *i    67.000000 + 67.000000 *i    67.000000 + 67.000000 *i    

67.000000 + 67.000000 *i    67.000000 + -67.000000 *i    67.000000 + -67.000000 *i    66.000000 + 0.000000 *i    67.000000 + 67.000000 *i    

67.000000 + 67.000000 *i    67.000000 + -67.000000 *i    67.000000 + -67.000000 *i      67.000000 + -67.000000 *i    66.000000 + 0.000000 *i    

EDIT 在 main() 中调用 srand 实际上解决了这个问题。谢谢各位。

[aft@centos-c physics-numaric]$ ./a.out 
31.000000 + 0.000000 *i    81.000000 + 75.000000 *i    81.000000 + 75.000000 *i     81.000000 + 75.000000 *i    81.000000 + 75.000000 *i    

81.000000 + -75.000000 *i    53.000000 + 0.000000 *i    69.000000 + 57.000000 *i    69.000000 + 57.000000 *i    69.000000 + 57.000000 *i    

69.000000 + 57.000000 *i    69.000000 + -57.000000 *i    27.000000 + 0.000000 *i    93.000000 + 11.000000 *i    93.000000 + 11.000000 *i    

93.000000 + 11.000000 *i    69.000000 + -57.000000 *i    93.000000 + -11.000000 *i    58.000000 + 0.000000 *i    76.000000 + 78.000000 *i    

76.000000 + 78.000000 *i    69.000000 + -57.000000 *i    93.000000 + -11.000000 *i    76.000000 + -78.000000 *i    67.000000 + 0.000000 *i    

【问题讨论】:

    标签: c linux gcc matrix libc


    【解决方案1】:

    不要在每次调用 rand 之前先调用 srand。程序启动时调用一次。

    【讨论】:

    • @aftnix:我认为有一个计时器,所以你只能在你提出问题 10 分钟后接受答案。
    • Charlseworth 人在这些堆栈交换应用程序设计背后确实付出了很多思考。很酷的动态:)
    • 我偶然点击了这个答案的“标志”。如何撤消?
    【解决方案2】:

    不要在循环内部调用srand。只调用一次。

    srand(time(NULL));
    for( ;i < MATSIZE; i++)
    {
        // ... calls to rand()   
    }
    

    否则,您使用相同的种子为随机生成器播种(因为它足够快以获得相同的时间)

    顺便说一句,很多时候我发现为我初始化很多东西的程序/序列创建一个 init 函数非常传统,包括随机生成(例如调用srand()

    【讨论】:

      【解决方案3】:

      您不想每次都使用srand() 为随机数生成器播种!只需在程序开始时调用一次。然后调用rand()获取下一个随机数。

      【讨论】:

        【解决方案4】:

        不要这样做:

        rand()%RAND_RANGE + 0*I;
        

        ,因为如果 RAND_RANGE 和 RAND_MAX+1 不​​相除,则会导致较低的值被过采样。 (“几乎总是”如此)

        另外:基于 time(NULL) 重启生成器在大多数情况下会以完全相同的值重启,因为 time_t 的粒度是一秒。

        最终:rand_max 将具有 至少 15 位 (32K) 的随机值。较旧的系统实际上可能仅提供 15 位,周期为 32 K。

        更新:这是来自wakkerbot 的 sn-p。 urnd() 函数尝试返回一个介于 0 和范围之间的无偏值。测试可能可以更优雅地执行。

        typedef unsigned long long BigThing;
        
        unsigned int urnd(unsigned int range)
        {
            static bool flag = FALSE;
        
            if (flag == FALSE) {
        #if defined(__mac_os) || defined(DOS)
                srand(time(NULL));
        #else
                srand48(time(NULL));
        #endif
            }
            flag = TRUE;
        #if defined(__mac_os) || defined(DOS)
            return rand()%range;
        #else
        
        if (range <= 1) return 0;
        
        while(1)        {
            BigThing val, box;
        #if WANT_RDTSC_RANDOM
            val = rdtsc_rand();
        #else
            val =  lrand48();
        #endif
        /* we need this to avoid oversampling of the lower values.
         * Oversampling the lower values becomes more of a problem if (UNSIGNED_MAX/range) gets smaller
         */
            box = val / range;
            if ((1+box) *range < range) continue;
            return val % range;
                }
        #endif
        }
        

        【讨论】:

        • 那么您的建议是什么?我应该如何取一个随机值并正确保持一个范围?
        • 这个想法是:如果你从范围的顶部获得一个样本,就在环绕发生之前:拒绝它并重新绘制。例如,如果 RAND_MAX 为 10,而您的 RAND_RANGE 为 4:拒绝值 >=8,否则返回 value%RAND_RANGE。 (否则值 {0,1} 在输出中出现的机会比 {2,3} 更大)我将在我的回复中添加一个 sn-p。
        猜你喜欢
        • 2013-05-31
        • 1970-01-01
        • 2011-03-24
        • 1970-01-01
        • 2019-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多