fork download
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. #include <math.h>
  5. // 蒙特卡洛模拟计算圆周率的函数
  6. // 参数:n_samples - 采样数,seed - 随机数种子
  7. double monte_carlo_pi(int n_samples, int seed) {
  8. // 设置随机数种子,保证每次模拟可复现
  9. srand(seed);
  10. int inside_circle = 0; // 记录落在单位圆内的点数
  11. for (int i = 0; i < n_samples; i++) {
  12. // 生成 [0,1) 范围内的随机坐标 (x,y)
  13. // rand() 生成 [0,RAND_MAX] 整数,除以 RAND_MAX 转换为浮点数
  14. double x = (double)rand() / RAND_MAX;
  15. double y = (double)rand() / RAND_MAX;
  16. // 判断点是否在单位圆内(x^2 + y^2 <= 1)
  17. if (x * x + y * y <= 1) {
  18. inside_circle++;
  19. }
  20. }
  21. // 圆周率估计值:pi = 4 * 圆内点数 / 总点数
  22. return 4.0 * inside_circle / n_samples;
  23. }
  24. // 计算样本标准差的函数(使用公式:sqrt( sum((xi-mean)^2) / (N-1) ))
  25. double calculate_stddev(double data[], int n) {
  26. double mean = 0.0;
  27. double sum_sq_diff = 0.0;
  28. // 先计算平均值
  29. for (int i = 0; i < n; i++) {
  30. mean += data[i];
  31. }
  32. mean /= n;
  33. // 再计算方差和
  34. for (int i = 0; i < n; i++) {
  35. double diff = data[i] - mean;
  36. sum_sq_diff += diff * diff;
  37. }
  38. // 样本标准差:除以 n-1
  39. return sqrt(sum_sq_diff / (n - 1));
  40. }
  41. int main() {
  42. // ===================== 第一部分:n=10000 时的模拟 =====================
  43. printf("===== 第一部分:采样数 n=10000 时的模拟 =====\n");
  44. int n1 = 10000;
  45. int seeds[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 10个不同种子
  46. double pi_results[10]; // 存储10次模拟结果
  47. // 10次模拟,输出每次结果
  48. for (int i = 0; i < 10; i++) {
  49. pi_results[i] = monte_carlo_pi(n1, seeds[i]);
  50. printf("种子 %2d | 计算得到的π = %.6f\n", seeds[i], pi_results[i]);
  51. }
  52. // 计算平均值和标准差
  53. double pi_mean = 0.0;
  54. for (int i = 0; i < 10; i++) {
  55. pi_mean += pi_results[i];
  56. }
  57. pi_mean /= 10;
  58. double pi_std = calculate_stddev(pi_results, 10);
  59. // 验证真实值是否在 [mean-std, mean+std] 区间内
  60. double true_pi = M_PI; // 系统内置的π常量
  61. double interval_low = pi_mean - pi_std;
  62. double interval_high = pi_mean + pi_std;
  63. int is_in_interval = (true_pi >= interval_low) && (true_pi <= interval_high);
  64. // 打印统计结果
  65. printf("\n----- 统计结果 -----\n");
  66. printf("π的平均值 μ = %.6f\n", pi_mean);
  67. printf("π的标准差 σ = %.6f\n", pi_std);
  68. printf("真实值 π = %.6f\n", true_pi);
  69. printf("真实值是否在 μ±σ 区间内? %s\n", is_in_interval ? "是" : "否");
  70. printf("==========================================\n\n");
  71. // ===================== 第二部分:不同采样数对精度的影响 =====================
  72. printf("===== 第二部分:不同采样数对精度的影响 =====\n");
  73. // 待测试的采样数列表
  74. int target_n_list[] = {40000, 250000, 1000000};
  75. int n_count = sizeof(target_n_list) / sizeof(target_n_list[0]);
  76. // 遍历不同采样数进行模拟
  77. for (int i = 0; i < n_count; i++) {
  78. int n = target_n_list[i];
  79. double current_pi_results[10];
  80. // 每个采样数下10次模拟
  81. for (int j = 0; j < 10; j++) {
  82. current_pi_results[j] = monte_carlo_pi(n, seeds[j]);
  83. }
  84. // 计算当前采样数下的平均值和标准差
  85. double current_mean = 0.0;
  86. for (int j = 0; j < 10; j++) {
  87. current_mean += current_pi_results[j];
  88. }
  89. current_mean /= 10;
  90. double current_std = calculate_stddev(current_pi_results, 10);
  91. // 理论精度:1/sqrt(n)(作业提示:精度正比于1/√n)
  92. double theoretical_precision = 1.0 / sqrt(n);
  93. // 打印结果
  94. printf("采样数 n = %7d | 平均π = %.6f | 标准差σ = %.6f | 理论精度1/√n = %.6f\n",
  95. n, current_mean, current_std, theoretical_precision);
  96. }
  97. return 0;
  98. }
Success #stdin #stdout 0.28s 5328KB
stdin
Standard input is empty
stdout
===== 第一部分:采样数 n=10000 时的模拟 =====
种子  1 | 计算得到的π = 3.171200
种子  2 | 计算得到的π = 3.157600
种子  3 | 计算得到的π = 3.152400
种子  4 | 计算得到的π = 3.135200
种子  5 | 计算得到的π = 3.174800
种子  6 | 计算得到的π = 3.124400
种子  7 | 计算得到的π = 3.148400
种子  8 | 计算得到的π = 3.137600
种子  9 | 计算得到的π = 3.126000
种子 10 | 计算得到的π = 3.148000

----- 统计结果 -----
π的平均值 μ = 3.147560
π的标准差 σ = 0.017254
真实值 π = 3.141593
真实值是否在 μ±σ 区间内? 是
==========================================

===== 第二部分:不同采样数对精度的影响 =====
采样数 n =   40000 | 平均π = 3.141730 | 标准差σ = 0.006143 | 理论精度1/√n = 0.005000
采样数 n =  250000 | 平均π = 3.141024 | 标准差σ = 0.002565 | 理论精度1/√n = 0.002000
采样数 n = 1000000 | 平均π = 3.141982 | 标准差σ = 0.001698 | 理论精度1/√n = 0.001000