Есть ли способ использования связанных списков, чтобы упростить мой код Монте-Карло - PullRequest
0 голосов
/ 10 сентября 2010

Привет, мой код в настоящее время имеет три функции, каждая из которых создает массив случайных чисел.Мне интересно, есть ли способ просто иметь одну функцию, возвращающую связанный список или многомерный массив, чтобы сделать его немного точнее:

(скопировано из 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 ]

6 голосов
/ 11 сентября 2010

Несколько баллов:

  1. Не определяйте RAND_MAX себя.
  2. main возвращает целое число.
  3. Только звоните srand один раз.
  4. Устраните дополнительные вызовы на srand и используйте одну функцию для инициализации ваших массивов.
  5. Вы определили X, Y и Z как массивы, но на самом деле использовали / нуждались только в одном значении каждое.
  6. Кажется, нет причин использовать динамическое распределение, поскольку размеры ваших массивов фиксированы.
4 голосов
/ 11 сентября 2010

Я не первый, кто указывает, что вам следует звонить srand только один раз, но я объясню почему :

Чем чаще вы звоните srand, тем меньше случайным образом получается rand.

Функция rand является генератором случайных чисел псевдо . Это означает, что он генерирует числа, которые выглядят случайными и имеют математические свойства, соответствующие случайности, но на самом деле они не случайны. Вывод rand на самом деле является фиксированной, полностью детерминированной последовательностью чисел.

Или, скорее, он производит одну из большого семейства полностью детерминированных последовательностей. Вы выбираете, какую из этих последовательностей вы хотите, предоставив начальное значение, используя srand. Когда вы дадите srand начальное число x, следующий вывод rand будет первым номером псевдослучайной (но полностью детерминированной!) Последовательности, идентифицированной начальным значением x. Другими словами:

int foo(int x)
{
   srand(x);
   return rand();
}

Возвращает разные значения для разных входов, но для данного x всегда будет возвращать одинаковое значение. Совсем не случайно!

Это на самом деле полезная функция, так как если вы обнаружите ошибку в программе, которая зависит от вывода rand, вы можете надежно воспроизвести ошибку, предоставив то же начальное значение для srand, чтобы получить то же самое последовательность из rand и то же поведение из вашей программы.

Причина, по которой вам нужно один раз вызвать srand, заключается в том, что в противном случае ваша программа всегда будет получать одинаковую последовательность чисел из rand (последовательность, указанная с помощью seed 1). Причина, по которой вы не хотите вызвать srand более одного раза (в большинстве случаев), заключается в том, что вы затем несколько раз заставляете rand возвращаться к началу его последовательностей, вместо того, чтобы дать ему один из их в полном объеме. Хотя любая заданная последовательность обладает свойствами случайности, последовательность начала последовательности не обязательно обладает этим свойством.

Очевидно, что особенно плохо, если вы повторно вызываете srand с одним и тем же seed, потому что тогда вы заставляете rand вернуться к началу одна и та же последовательность каждый раз, поэтому rand всегда будет выдавать одинаковое значение - именно то, что вам не нужно.

Причина, по которой вы обычно видите srand(time(NULL)), заключается в том, что время, вероятно, будет различным для любых двух вызовов данной программы, что означает, что при каждом запуске программы будет использоваться другая псевдослучайная последовательность. Но time возвращает время только с точностью до секунд, поэтому, если вы делаете это несколько раз в течение одного вызова программы, как у вас, и между вызовами srand проходит менее одной секунды, вы будете повторно - посев с тем же семенем, с нелепыми результатами, как вы наблюдали.

Итог: звоните srand ровно один раз, перед первым использованием rand. Поверьте, что разработчики библиотеки C написали приличный генератор псевдослучайных чисел, и не пытайтесь «увеличить случайность», пытаясь компенсировать проблемы, которых не существует.

1 голос
/ 11 сентября 2010

Другие люди уже решили некоторые проблемы с вашей программой, но понимаете ли вы, что каждый раз, когда вы запускаете ее, вы теряете более 10 мегабайт памяти? бесплатно () ...

1 голос
/ 11 сентября 2010

Только вызов srand() один раз за вызов программы, обычно внутри main().

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

    /* rest of program, with no more calls to srand() */
}
1 голос
/ 11 сентября 2010

Единственная разница между вашими тремя функциями заключается в том, как они вызывают sleep().Конечно, вы можете свернуть все три в одну функцию и вызывать ее три раза в цикле?

...