You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在蒙特卡洛法计算圆周率时使用100万采样点而不崩溃?

解决蒙特卡洛计算圆周率大样本点崩溃的问题

嘿,我来帮你搞定这个问题!你程序崩溃的核心原因其实和编译器无关,是内存分配方式出了问题——咱们一步步来看:

为什么超过10万采样点就崩溃?

你代码里用了变长数组(VLA),比如float x[dot]、float y[dot]这些,这些数组是分配在栈上的。而栈的空间非常有限,Linux系统默认一般只有8MB左右,Windows可能更小。

当dot达到100万时,光是x、y、distance、pi这四个float数组加起来就需要:
1,000,000 * 4字节 * 4 = 16MB,这远远超过了栈的默认容量,直接导致栈溢出(Stack Overflow),程序自然就崩溃了。

两种解决方案,推荐第二种更高效的

方案1:改用堆内存分配

堆的空间比栈大得多(可以用到系统大部分可用内存),我们用malloc在堆上分配数组,用完记得用free释放:

#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 *x = malloc(dot * sizeof(float));
    float *y = malloc(dot * sizeof(float));
    float *distance = malloc(dot * sizeof(float));
    float *pi = malloc(dot * sizeof(float));

    if (!x || !y || !distance || !pi) {
        fprintf(stderr, "内存分配失败!\n");
        return 1;
    }

    // 生成x坐标
    for (int i = 0; i < dot; i++) {
        x[i] = (float)rand() / (float)RAND_MAX;
    }
    // 生成y坐标
    for (int i = 0; i < dot; i++) {
        y[i] = (float)rand() / (float)RAND_MAX;
    }

    // 计算距离
    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++;
    }

    // 计算Pi值
    for (int i = 0; i < dot; ++i) {
        pi[i] = (float)dotC / (float)dotS * 4;
    }

    printf("approximation of Pi is: %f\n", pi[0]);

    // 释放堆内存,避免内存泄漏
    free(x);
    free(y);
    free(distance);
    free(pi);

    return 0;
}

方案2:彻底优化代码,完全不用数组(强烈推荐)

其实你的代码里,所有数组都是多余的!我们根本不需要存储所有点的坐标、距离和Pi值,完全可以边生成点边计算,这样内存占用几乎为0,不管多少采样点都不会崩溃,还能提升运行速度:

#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

int main() {
    srand(time(NULL));
    int dot;
    int dotC = 0;

    printf("How many dot do you want to use?: ");
    scanf("%d", &dot);

    for (int i = 0; i < dot; ++i) {
        // 直接生成当前点的x、y,不用存储
        float x = (float)rand() / (float)RAND_MAX;
        float y = (float)rand() / (float)RAND_MAX;
        // 这里用距离平方比较,省去开根号的计算,更快!
        float dist_sq = x*x + y*y;
        if (dist_sq < 1.0f) {
            dotC++;
        }
    }

    // 直接计算最终Pi值
    float pi = (float)dotC / dot * 4.0f;
    printf("approximation of Pi is: %f\n", pi);

    return 0;
}

这个版本的好处:

  • 内存占用极小,完全避免栈溢出问题
  • 运行效率更高:去掉了数组的存储和遍历,还省去了sqrt的计算(比较距离平方和1的大小,结果和比较距离与1完全一致)

额外小提示

如果以后需要处理超大数量的采样点(比如1e9),int类型可能会溢出,建议把dot和dotC改成long long类型,避免数值溢出。

内容的提问来源于stack exchange,提问作者Francesco Procopio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 06:17:46