为什么在使用 PRNG 估算 Pi 时总是得到 2.8284?
Why I always get 2.8284 when estimating Pi using PRNGs?
我是 C++ 新手。我正在尝试使用计算机系统的随机数生成器根据 Ernesto Cesaro 定理统计确定 Pi 的值。但是我现在所做的可以输入一个种子数并生成100个伪随机数,然后估计pi的值。生成器可以生成不同组的伪随机数。然而,令人困惑的是,我总是得到 2.8284 的圆周率估计值,没有任何变化。这是代码:
#include <iostream>
#include <math.h>
using namespace std;
int main()
{
int seed;
cout << "input a seed number: " << endl;
cin >> seed;
srand(seed);
int i, a[100];
for (i = 0; i < 100; i++)
a[i] = rand() % 100 + 1;
cout << "The generated random numbers are: " << endl;
for (i = 0; i < 100; i++)
cout << a[i] << "\t";
int m, n, j, r;
int sum = 0;
for (j = 0; j < 100; j++)
{
m = a[j];
n = a[j + 1];
j = j + 2;
do
{
r = m%n;
m = n;
n = r;
} while (r != 0);
if (n = 1)
sum = sum + 1;
}
double Pi, p;
p = 300 / sum;
Pi = sqrt(p);
cout << "The estimate value of Pi is: " << Pi << endl;
system("pause");
return 0;
}
请注意,Cesaro 定理指出给定两个随机整数 x 和 y,gcd(x, y) = 1 的概率为 6/(Pi^2)。并且使用的 PRNG 会影响结果估计与 Pi(3.1416) 的接近程度。
您的代码存在几个问题。
问题 #1:
if (n = 1)
它应该是 if (n == 1)
否则你将 1
分配给 n
并且总是评估为真。
问题 #2:
n = r;
} while (r != 0);
if (n == 1)
仔细想想,只有当r
为0
时,循环才会结束,但随后n
也会为0
,因为最后一行循环。所以 n
永远不会等于 1
。你可能想要 if (m == 1)
.
问题 #3:
for (j = 0; j < 100; j++)
{
...
j = j + 2;
您正在递增 for
行和循环体中的 j
。你只需要一个。
for (j = 0; j < 100; j += 2)
{
//no j increment
问题 #4:
p = 300 / sum;
那是整数除法,因为两个数都是整数。你想要浮点数:p = 300.0 / sum;
.
通过这些更改,我得到了大约 3.16
。
你的算法有两个错误。 (不是四个 :p )
首先 - 当 gcd 不大于 1 时,数字是互质的,您还应该检查 m
值而不是 n
(请参阅罗德里戈的回答)。因此,您需要将 if 更改为:
if (m <= 1)
sum = sum + 1; // ++sum;
第二个错误是您的估算器:p = 300 / sum;
。你为什么用300?正确的是:
float pi = sqrt ( 6.f * iterations / sum) // from p = 6 / pi^2
您代码中的 iterations
是 34(因为您更改了循环体中的 j
-index)。
问题是你弄错了形状。您成功估计了正方形的周长与其对角线的比率,而不是圆的周长与其直径 (pi) 的比率。
即边长为 1 的正方形周长为 4,对角线为:
sqrt(1^2+1^2) = sqrt(2)
因此,圆周与对角线的比率为:
4:sqrt(2) = 2.8284
把正方形改成圆形应该就对了
我是 C++ 新手。我正在尝试使用计算机系统的随机数生成器根据 Ernesto Cesaro 定理统计确定 Pi 的值。但是我现在所做的可以输入一个种子数并生成100个伪随机数,然后估计pi的值。生成器可以生成不同组的伪随机数。然而,令人困惑的是,我总是得到 2.8284 的圆周率估计值,没有任何变化。这是代码:
#include <iostream>
#include <math.h>
using namespace std;
int main()
{
int seed;
cout << "input a seed number: " << endl;
cin >> seed;
srand(seed);
int i, a[100];
for (i = 0; i < 100; i++)
a[i] = rand() % 100 + 1;
cout << "The generated random numbers are: " << endl;
for (i = 0; i < 100; i++)
cout << a[i] << "\t";
int m, n, j, r;
int sum = 0;
for (j = 0; j < 100; j++)
{
m = a[j];
n = a[j + 1];
j = j + 2;
do
{
r = m%n;
m = n;
n = r;
} while (r != 0);
if (n = 1)
sum = sum + 1;
}
double Pi, p;
p = 300 / sum;
Pi = sqrt(p);
cout << "The estimate value of Pi is: " << Pi << endl;
system("pause");
return 0;
}
请注意,Cesaro 定理指出给定两个随机整数 x 和 y,gcd(x, y) = 1 的概率为 6/(Pi^2)。并且使用的 PRNG 会影响结果估计与 Pi(3.1416) 的接近程度。
您的代码存在几个问题。
问题 #1:
if (n = 1)
它应该是 if (n == 1)
否则你将 1
分配给 n
并且总是评估为真。
问题 #2:
n = r;
} while (r != 0);
if (n == 1)
仔细想想,只有当r
为0
时,循环才会结束,但随后n
也会为0
,因为最后一行循环。所以 n
永远不会等于 1
。你可能想要 if (m == 1)
.
问题 #3:
for (j = 0; j < 100; j++)
{
...
j = j + 2;
您正在递增 for
行和循环体中的 j
。你只需要一个。
for (j = 0; j < 100; j += 2)
{
//no j increment
问题 #4:
p = 300 / sum;
那是整数除法,因为两个数都是整数。你想要浮点数:p = 300.0 / sum;
.
通过这些更改,我得到了大约 3.16
。
你的算法有两个错误。 (不是四个 :p )
首先 - 当 gcd 不大于 1 时,数字是互质的,您还应该检查 m
值而不是 n
(请参阅罗德里戈的回答)。因此,您需要将 if 更改为:
if (m <= 1)
sum = sum + 1; // ++sum;
第二个错误是您的估算器:p = 300 / sum;
。你为什么用300?正确的是:
float pi = sqrt ( 6.f * iterations / sum) // from p = 6 / pi^2
您代码中的 iterations
是 34(因为您更改了循环体中的 j
-index)。
问题是你弄错了形状。您成功估计了正方形的周长与其对角线的比率,而不是圆的周长与其直径 (pi) 的比率。
即边长为 1 的正方形周长为 4,对角线为:
sqrt(1^2+1^2) = sqrt(2)
因此,圆周与对角线的比率为:
4:sqrt(2) = 2.8284
把正方形改成圆形应该就对了