#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
// 蒙特卡洛模拟计算圆周率的函数
// 参数:n_samples - 采样数,seed - 随机数种子
double monte_carlo_pi(int n_samples, int seed) {
// 设置随机数种子,保证每次模拟可复现
srand(seed);
int inside_circle = 0; // 记录落在单位圆内的点数
for (int i = 0; i < n_samples; i++) {
// 生成 [0,1) 范围内的随机坐标 (x,y)
// rand() 生成 [0,RAND_MAX] 整数,除以 RAND_MAX 转换为浮点数
double x = (double)rand() / RAND_MAX;
double y = (double)rand() / RAND_MAX;
// 判断点是否在单位圆内(x^2 + y^2 <= 1)
if (x * x + y * y <= 1) {
inside_circle++;
}
}
// 圆周率估计值:pi = 4 * 圆内点数 / 总点数
return 4.0 * inside_circle / n_samples;
}
// 计算样本标准差的函数(使用公式:sqrt( sum((xi-mean)^2) / (N-1) ))
double calculate_stddev(double data[], int n) {
double mean = 0.0;
double sum_sq_diff = 0.0;
// 先计算平均值
for (int i = 0; i < n; i++) {
mean += data[i];
}
mean /= n;
// 再计算方差和
for (int i = 0; i < n; i++) {
double diff = data[i] - mean;
sum_sq_diff += diff * diff;
}
// 样本标准差:除以 n-1
return sqrt(sum_sq_diff / (n - 1));
}
int main() {
// ===================== 第一部分:n=10000 时的模拟 =====================
printf("===== 第一部分:采样数 n=10000 时的模拟 =====\n");
int n1 = 10000;
int seeds[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 10个不同种子
double pi_results[10]; // 存储10次模拟结果
// 10次模拟,输出每次结果
for (int i = 0; i < 10; i++) {
pi_results[i] = monte_carlo_pi(n1, seeds[i]);
printf("种子 %2d | 计算得到的π = %.6f\n", seeds[i], pi_results[i]);
}
// 计算平均值和标准差
double pi_mean = 0.0;
for (int i = 0; i < 10; i++) {
pi_mean += pi_results[i];
}
pi_mean /= 10;
double pi_std = calculate_stddev(pi_results, 10);
// 验证真实值是否在 [mean-std, mean+std] 区间内
double true_pi = M_PI; // 系统内置的π常量
double interval_low = pi_mean - pi_std;
double interval_high = pi_mean + pi_std;
int is_in_interval = (true_pi >= interval_low) && (true_pi <= interval_high);
// 打印统计结果
printf("\n----- 统计结果 -----\n");
printf("π的平均值 μ = %.6f\n", pi_mean);
printf("π的标准差 σ = %.6f\n", pi_std);
printf("真实值 π = %.6f\n", true_pi);
printf("真实值是否在 μ±σ 区间内? %s\n", is_in_interval ? "是" : "否");
printf("==========================================\n\n");
// ===================== 第二部分:不同采样数对精度的影响 =====================
printf("===== 第二部分:不同采样数对精度的影响 =====\n");
// 待测试的采样数列表
int target_n_list[] = {40000, 250000, 1000000};
int n_count = sizeof(target_n_list) / sizeof(target_n_list[0]);
// 遍历不同采样数进行模拟
for (int i = 0; i < n_count; i++) {
int n = target_n_list[i];
double current_pi_results[10];
// 每个采样数下10次模拟
for (int j = 0; j < 10; j++) {
current_pi_results[j] = monte_carlo_pi(n, seeds[j]);
}
// 计算当前采样数下的平均值和标准差
double current_mean = 0.0;
for (int j = 0; j < 10; j++) {
current_mean += current_pi_results[j];
}
current_mean /= 10;
double current_std = calculate_stddev(current_pi_results, 10);
// 理论精度:1/sqrt(n)(作业提示:精度正比于1/√n)
double theoretical_precision = 1.0 / sqrt(n);
// 打印结果
printf("采样数 n = %7d | 平均π = %.6f | 标准差σ = %.6f | 理论精度1/√n = %.6f\n",
n, current_mean, current_std, theoretical_precision);
}
return 0;
}