有没有办法使用链表来简化我的蒙特卡罗代码

时间:2010-09-10 19:55:37

标签: c linked-list montecarlo

Hiya,我的代码目前有三个函数,每个函数都会产生大量的随机数。我想知道是否有一种方法只需要一个函数返回一个链表或多维数组,使其有点整洁:

(从http://pastebin.com/Y5aE6XKS复制)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#ifndef RAND_MAX
#define RAND_MAX 2147483648
#endif
#define N 420000

double* rdm_X(void);
double* rdm_Y(void);
double* rdm_Z(void);

void main(void)
{
   double* Random_number_list_X = rdm_X();
   double* Random_number_list_Y = rdm_Y();
   double* Random_number_list_Z = rdm_Z();
   double X[N+1], Y[N+1], Z[N+1], density = 1, vol = 42.0;
   double sum = 0, sum_x = 0, sum_y = 0, sum_z = 0;
   int i;

   for (i = 0; i <= N; i++) {
      X[i] = 3 * Random_number_list_X[i] + 1;
      Y[i] = 7 * Random_number_list_Y[i] - 3;
      Z[i] = 2 * Random_number_list_Z[i] - 1;
      if ((Z[i]*Z[i]) + (sqrt(X[i]*X[i] + Y[i]*Y[i]) - 3)*(sqrt(X[i]*X[i] + Y[i]*Y[i]) - 3) <= 1) {
         sum += density;
         sum_x += X[i] * density;
         sum_y += Y[i] * density;
         sum_z += Z[i] * density;
      }
   }
   printf("(%.5lf, %.5lf, %.5lf)\n",
            sum_x/sum, sum_y/sum, sum_z/sum);
}

double* rdm_X(void)
{
   double* Random_number_list_X = calloc(N + 1, sizeof(double));
   int i;

   srand(time(NULL));
   for (i = 1; i <= N; i++) {
      Random_number_list_X[i] = (float) rand() / (float) RAND_MAX;
   }
   return Random_number_list_X;
}

double* rdm_Y(void)
{
   double* Random_number_list_Y = calloc(N + 1, sizeof(double));
   int i;
   sleep(1);
   srand(time(NULL));
   for (i = 1; i <= N; i++) {
      Random_number_list_Y[i] = (float) rand() / (float) RAND_MAX;
   }
   return Random_number_list_Y;
}

double* rdm_Z(void)
{
   double* Random_number_list_Z = calloc(N + 1, sizeof(double));
   int i;
   sleep(2);
   srand(time(NULL));
   for (i = 1; i <= N; i++) {
      Random_number_list_Z[i] = (float) rand() / (float) RAND_MAX;
   }
   return Random_number_list_Z;
}

5 个答案:

答案 0 :(得分:6)

几点:

  1. 不要自己定义RAND_MAX
  2. main返回一个int。
  3. 只能拨打srand一次。
  4. 消除对srand的额外调用,并使用一个函数初始化阵列。
  5. 您将X,Y和Z定义为数组,但实际上每个只使用/需要一个值。
  6. 似乎没有理由使用动态分配,因为您的数组大小是固定的。

答案 1 :(得分:4)

我不是第一个指出你应该只调用srand一次的人,但我会解释为什么

srand的输出越频繁地rand less 随机调用。

rand函数是 - 随机数生成器。这意味着它生成看起来随机的数字,并且具有与随机性相对应的数学属性,但它们实际上并不是随机的。 rand的输出实际上是一个固定的,完全确定的数字序列。

或者,它产生了一大类完全确定性序列中的一个。您可以使用srand提供“种子”值来选择所需的序列中的哪一个。当您为srand提供种子x时,rand的下一个输出将是种子{{1}标识的伪随机(但完全确定的!)序列的第一个数字}。换句话说:

x

将为不同的输入返回不同的值,但对于给定的int foo(int x) { srand(x); return rand(); } ,将始终返回相同的值。一点也不随便!

这实际上是一个有用的功能,因为如果您发现某个程序中的错误依赖于x的输出,您可以通过向rand提供相同的种子来可靠地重现该错误从srand获取相同的序列,从而使你的程序具有相同的行为。

您需要拨打rand一次的原因是因为否则您的程序将始终从srand(由种子rand标识的序列)接收相同的数字序列。你想要多次调用1的原因(在大多数情况下)是因为你反复强迫srand回到序列的开头而不是让它它给你一个完整的。虽然任何给定序列都具有随机性,但序列开始序列不一定具有此属性。

显然,如果你使用相同的种子反复调用rand,那么尤其不好,因为那样你就迫使srand回到了每次开始相同的序列,因此rand将始终生成相同的值 - 正是您不想要的。

您经常看到rand的原因是因为给定程序的任何两次调用之间的时间可能不同,这意味着每次程序运行时它将使用不同的伪随机序列。但是srand(time(NULL))只返回粒度为秒的时间,所以如果你在一个程序的单次调用中重复这样做,就像在你的程序中一样,并且在调用time之间不到一秒钟,你正如你所观察到的那样,将会用同样的种子反复播种,结果非常荒谬。

底线:在您第一次使用srand之前,只需拨打srand一次。相信C库的实现者编写了一个体面的伪随机数生成器,并且不试图通过尝试补偿不存在的问题来“增加随机性”。

答案 2 :(得分:1)

您的三个功能之间的唯一区别是他们如何调用sleep()。当然你可以把所有三个都折叠成一个函数,并在一个循环中调用它三次?

答案 3 :(得分:1)

每次程序调用只能调用srand() 一次,通常在main()内。

int main(void) {
    /* initializations */
    srand(time(NULL));

    /* rest of program, with no more calls to srand() */
}

答案 4 :(得分:1)

其他人已经解决了您的程序的一些问题,但是您是否意识到每次运行它时泄漏超过10兆字节的内存?自由()...