是否有一种使用链接列表来简化我的蒙特卡洛代码的方法
-
02-10-2019 - |
题
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;
}
解决方案
我不是第一个指出你只应该打电话的人 srand
曾经,但我会解释 为什么:
您打电话越多 srand
这 较少的 随机输出 rand
是。
这 rand
功能是 伪- 随机数生成器。这意味着它会生成看起来随机的数字,并且具有与随机性相对应的数学属性,但实际上并非随机。输出 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
回到开始 相同的 每次序列,所以 rand
总是会产生 相同的 价值 - 正是您不想要的。
您通常看到的原因 srand(time(NULL))
是因为给定程序的任何两个调用之间的时间可能会有所不同,这意味着每次程序运行时,都会使用不同的伪和序列。但 time
仅将时间返回到粒度的时间,因此,如果您在程序的单个调用中反复进行此操作,如在您的程序中,并且在调用之间不到一秒钟的时间 srand
, ,正如您所观察到的那样,您将反复以相同的种子重新种子,并以荒谬的结果重新种子。
底线:致电 srand
恰恰是一次,在您第一次使用之前 rand
. 。相信C库的实施者写了一个不错的伪随机数生成器,并且不要试图通过尝试补偿不存在的问题来“增加随机性”。
其他提示
几点:
- 不要定义
RAND_MAX
你自己。 main
返回int。- 只会打电话
srand
一次。 - 消除额外的电话
srand
, ,并使用一个功能来初始化您的数组。 - 您将x,y和z定义为数组,但实际上只使用/需要一个值。
- 似乎没有理由使用动态分配,因为您的阵列大小是固定的。
您的三个功能之间的唯一区别是他们如何称呼 sleep()
. 。当然,您可以将这三个功能崩溃成一个函数,并在循环中称其为三次?
只会打电话 srand()
一次 每个程序调用,通常在内部 main()
.
int main(void) {
/* initializations */
srand(time(NULL));
/* rest of program, with no more calls to srand() */
}
其他人已经解决了您的程序的一些问题,但是您是否意识到每次运行时都会泄漏10兆字节的内存?自由()...