Есть ли способ использования связанных списков для упрощения моего кода Monte-Carlo

StackOverflow https://stackoverflow.com/questions/3687881

  •  02-10-2019
  •  | 
  •  

Вопрос

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

(скопирован из 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;
}
Это было полезно?

Решение

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

Чем чаще вы называете srand то меньше случайный выход rand является.

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

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

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

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

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

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

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

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

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

Другие советы

Несколько очков:

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top