如何解决我如何使用超过 100.000 点?
我制作了这个项目,它可以使用蒙特卡罗方法计算 Pi,但如果我使用超过 100.000 个点,它会崩溃。有谁知道如何使用 1.000.000 点而不崩溃?我正在使用 GNU 编译器。我试过使用另一个编译器,但我遇到了同样的问题。
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main() {
srand(time(NULL));
int dot;
int dotC = 0;
int dotS = 0;
printf("How many dot do you want to use?: ");
scanf("%d",&dot);
float pi[dot];
float x[dot];
float y[dot];
for (int i = 1; i < dot; i++) {
x[i] = (float)rand() / (float)RAND_MAX;
}
for (int i = 0; i < dot; i++) {
y[i] = (float)rand() / (float)RAND_MAX;
}
float distance[dot];
for (int i = 0; i < dot; ++i) {
distance[i] = sqrt(pow(x[i],2) + pow(y[i],2));
}
for (int i = 0; i < dot; ++i) {
if (distance[i] < 1) {
dotC++;
}
dotS++;
}
for (int i = 0; i < dot; ++i) {
pi[i] = (float)dotC / (float)dotS * 4;
}
printf("approximation of PY is: ");
printf("%f\n",pi[0]);
}
解决方法
您会遇到堆栈溢出,因为您分配的大数组具有自动存储(即在堆栈上),超出了程序可用的堆栈空间。
您可以通过使用 malloc()
或 calloc()
从堆中分配这些来解决问题,但您可以通过根本不使用数组来简化算法:
- 对于每个随机点,计算距离并更新
dotC
和dotS
计数器。无需存储值。 - 初始化
x
数组的循环应该从0
开始。您有未定义的行为,因为您没有初始化x[0]
。 -
dotS
实际上是多余的,因为它的最终值与dot
相同。 - 为了提高精度,您应该使用
double
而不是float
。 - 您应该使用简单的乘法而不是成本更高的
pow()
函数。 - 也不需要
sqrt()
:将距离的平方与1.0
进行比较得出相同的结果。
这是一个简化版本:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL));
int dots;
int dotC = 0;
printf("How many dots do you want to use?: ");
if (scanf("%d",&dots) != 1)
return 1;
for (int i = 0; i < dots; i++) {
double x = (double)rand() / (double)RAND_MAX;
double y = (double)rand() / (double)RAND_MAX;
if (x * x + y * y <= 1.0)
dotC++;
}
printf("approximation of PI is: %.9f\n",4 * (double)dotC / (double)dots);
return 0;
}
在具有慢浮点数的系统上,您可以将 for
循环更改为使用 64 位整数并产生相同的结果:
for (int i = 0; i < dots; i++) {
long long x = rand();
long long y = rand();
if (x * x + y * y <= (long long)RAND_MAX * RAND_MAX)
dotC++;
}
这个算法真的是伪随机数生成器的一个基准,在我的旧 Macbook 和 Apple libC 上运行 10 亿个点只在 13 秒内产生 4 或 5 个小数位。整数或浮点版本在此 CPU 上以相同速度运行。
,如果你想动态分配数组,你应该使用malloc。替换:
float *pi,*x,*y;
x = malloc(dot * sizeof(float));
if (x==NULL) {
printf("no memory for x\n");
exit(1);
}
y = malloc(dot * sizeof(float));
if (y==NULL) {
printf("no memory for y\n");
exit(1);
}
pi = malloc(dot * sizeof(float));
if (pi==NULL) {
printf("no memory for pi\n");
exit(1);
}
这会起作用,但是,对于大数字,它会耗尽内存。也许你可以计算增量?为什么要存储所有计算?也许算法对我来说不够清楚,但我想应该是可能的......
我再次查看了您的代码,这似乎也是如此:
int main(){
srand(time(NULL));
int dot;
int dotC = 0;
int dotS = 0;
printf("How mmany dot do you want to use?: ");
scanf("%d",&dot);
float pi,x,y;
for (int i = 0; i < dot ; i++){
x = (float)rand()/(float)RAND_MAX;
y = (float)rand()/(float)RAND_MAX;
if (sqrt(pow(x,2) + pow(y,2)) < 1)
{
dotC++;
}
dotS++;
}
printf("approximation of PY is: %f\n",dotC / (float)dotS * 4);
}
,
当 float distance[dot]
太大时,您可能会因动态数组分配(如 dot
)而溢出堆栈(因此是此网站名称)。为了解决这个问题,您可以增加堆栈大小(但您会遇到更大的数字问题)或在堆上分配数组,例如。
float * x = calloc(dot,sizeof(float));
float * y = calloc(dot,sizeof(float));
/* ... */
free(x);
free(y);
通常还建议检查 calloc
的 NULL
返回值,请参阅 man calloc
。
虽然其他答案正确且更合理,但如果您在 stack size limit
上,您始终可以使用 ulimit
命令暂时增加 UNIX
。这将允许多几个小数。
使用 ulimit -s
或 ulimit -a
获取当前堆栈大小以获取更多信息。
然后您可以通过键入 ulimit -H -s
或 ulimit -H -a
了解更多信息来找到堆栈的最大大小。
最后,您可以通过键入 ulimit -s maxsize
将堆栈大小设置为最大值,maxsize 等于您键入 ulimit -H -s
时获得的数字。
当您终止 shell 时,堆栈大小将重置为其默认值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。