This is a C++ implementation of a simple Monte Carlo simulation to approximate the value of pi. The program uses the standard library Mersenne twister engine to generate two random numbers between -1.0 to 1.0, one for x and one for y, for each point generated.
Every time the Point
class constructor is called it checks to see if the values passed in satisfy the equation:
$$x^2 + y^2 = 1$$
If it does, both the number of points and the number of points within the circle increase by one. If not, only the total number of points is increased.
The program operates on the property that a circle inscribed within a unit square has an area of pi/4 so I divide the number of points in the circle by the total number of points and then multiply by four to get the approximate value of pi.
/** Monte Carlo Simulation to estimate the value of PI
*
*/
unsigned long long totalPoints = 0;
unsigned long long pointsInCircle = 0;
unsigned long long overallTotalPoints = 0;
unsigned long long overallPointsInCircle = 0;
#include "includes\Main.hpp"
const long double actualPI = 3.14159265359;
long double approximatePI(unsigned long long inCircle, unsigned long long total);
void printPercentError(const long double myPI, const long double actualPI);
int main()
{
system("cls");
int zeroCounter = 0;
int currentIteration = 0;
long double myPI = 0;
// Test Parameters
const int M = 50; // Simulations per program execution
const int N = 20'000'000; // Points per simulation
for (int i = 0; i < M; ++i) {
totalPoints = 0;
pointsInCircle = 0;
srand(time(NULL));
static ::std::random_device rd;
static std::mt19937_64 rng(rand());
static std::uniform_real_distribution<double> uid1(-1.0,1.0); // x
static std::uniform_real_distribution<double> uid2(-1.0,1.0); // y
for (int j = 0; j < N; ++j) {
Point p([&]{
return uid1(rng);
}(), [&]{
return uid2(rng);
}());
}
std::cout << "Iteration: " << currentIteration + 1 << std::endl;
std::cout << "Points in circle: " << pointsInCircle << std::endl;
std::cout << "Total points: " << totalPoints << std::endl;
printf("PI: %.10Le\n", approximatePI(pointsInCircle, totalPoints));
myPI += approximatePI(overallPointsInCircle, overallTotalPoints);
++currentIteration;
// Divide myPI every 5 iterations to put off an overflow for as long as possible
if (zeroCounter % 5 == 0) {
if (currentIteration == M) {
// Do not zero out myPI
} else {
myPI /= 5;
zeroCounter = 0;
overallTotalPoints = 0;
overallPointsInCircle = 0;
}
}
printf("\n");
}
printf("\n\n");
std::cout << "Points in circle overall: " << overallPointsInCircle << std::endl;
std::cout << "Total points overall: " << overallTotalPoints << std::endl;
myPI = approximatePI(overallPointsInCircle, overallTotalPoints);
printf("PI: %.10Le\n", myPI);
printPercentError(myPI, actualPI);
return EXIT_SUCCESS;
}
long double approximatePI(const unsigned long long inCircle, const unsigned long long total)
{
return (((long double) inCircle / (long double) total) * 4);
}
void printPercentError(const long double myPI, const long double actualPI)
{
printf("\n\tPercent Error: %.10Le%%\n", 100 * ((myPI - actualPI) / actualPI));
}
Output:
Iteration: 1
Points in circle: 15708507
Total points: 20000000
PI: 3.1417014000e+000
Iteration: 2
Points in circle: 15708384
Total points: 20000000
PI: 3.1416768000e+000
Iteration: 3
Points in circle: 15705582
Total points: 20000000
PI: 3.1411164000e+000
Iteration: 4
Points in circle: 15710275
Total points: 20000000
PI: 3.1420550000e+000
Iteration: 5
Points in circle: 15706656
Total points: 20000000
PI: 3.1413312000e+000
Iteration: 6
Points in circle: 15705987
Total points: 20000000
PI: 3.1411974000e+000
Iteration: 7
Points in circle: 15709017
Total points: 20000000
PI: 3.1418034000e+000
Iteration: 8
Points in circle: 15706029
Total points: 20000000
PI: 3.1412058000e+000
Iteration: 9
Points in circle: 15707857
Total points: 20000000
PI: 3.1415714000e+000
Iteration: 10
Points in circle: 15709423
Total points: 20000000
PI: 3.1418846000e+000
Iteration: 11
Points in circle: 15708768
Total points: 20000000
PI: 3.1417536000e+000
Iteration: 12
Points in circle: 15708054
Total points: 20000000
PI: 3.1416108000e+000
Iteration: 13
Points in circle: 15706587
Total points: 20000000
PI: 3.1413174000e+000
Iteration: 14
Points in circle: 15706242
Total points: 20000000
PI: 3.1412484000e+000
Iteration: 15
Points in circle: 15705368
Total points: 20000000
PI: 3.1410736000e+000
Iteration: 16
Points in circle: 15706917
Total points: 20000000
PI: 3.1413834000e+000
Iteration: 17
Points in circle: 15708899
Total points: 20000000
PI: 3.1417798000e+000
Iteration: 18
Points in circle: 15706711
Total points: 20000000
PI: 3.1413422000e+000
Iteration: 19
Points in circle: 15709541
Total points: 20000000
PI: 3.1419082000e+000
Iteration: 20
Points in circle: 15710444
Total points: 20000000
PI: 3.1420888000e+000
Iteration: 21
Points in circle: 15706853
Total points: 20000000
PI: 3.1413706000e+000
Iteration: 22
Points in circle: 15712085
Total points: 20000000
PI: 3.1424170000e+000
Iteration: 23
Points in circle: 15710104
Total points: 20000000
PI: 3.1420208000e+000
Iteration: 24
Points in circle: 15709046
Total points: 20000000
PI: 3.1418092000e+000
Iteration: 25
Points in circle: 15707144
Total points: 20000000
PI: 3.1414288000e+000
Iteration: 26
Points in circle: 15707643
Total points: 20000000
PI: 3.1415286000e+000
Iteration: 27
Points in circle: 15707230
Total points: 20000000
PI: 3.1414460000e+000
Iteration: 28
Points in circle: 15708895
Total points: 20000000
PI: 3.1417790000e+000
Iteration: 29
Points in circle: 15708037
Total points: 20000000
PI: 3.1416074000e+000
Iteration: 30
Points in circle: 15706278
Total points: 20000000
PI: 3.1412556000e+000
Iteration: 31
Points in circle: 15707066
Total points: 20000000
PI: 3.1414132000e+000
Iteration: 32
Points in circle: 15705930
Total points: 20000000
PI: 3.1411860000e+000
Iteration: 33
Points in circle: 15708086
Total points: 20000000
PI: 3.1416172000e+000
Iteration: 34
Points in circle: 15710387
Total points: 20000000
PI: 3.1420774000e+000
Iteration: 35
Points in circle: 15706093
Total points: 20000000
PI: 3.1412186000e+000
Iteration: 36
Points in circle: 15707002
Total points: 20000000
PI: 3.1414004000e+000
Iteration: 37
Points in circle: 15709261
Total points: 20000000
PI: 3.1418522000e+000
Iteration: 38
Points in circle: 15709620
Total points: 20000000
PI: 3.1419240000e+000
Iteration: 39
Points in circle: 15705817
Total points: 20000000
PI: 3.1411634000e+000
Iteration: 40
Points in circle: 15708118
Total points: 20000000
PI: 3.1416236000e+000
Iteration: 41
Points in circle: 15706553
Total points: 20000000
PI: 3.1413106000e+000
Iteration: 42
Points in circle: 15710051
Total points: 20000000
PI: 3.1420102000e+000
Iteration: 43
Points in circle: 15706290
Total points: 20000000
PI: 3.1412580000e+000
Iteration: 44
Points in circle: 15706712
Total points: 20000000
PI: 3.1413424000e+000
Iteration: 45
Points in circle: 15707375
Total points: 20000000
PI: 3.1414750000e+000
Iteration: 46
Points in circle: 15707948
Total points: 20000000
PI: 3.1415896000e+000
Iteration: 47
Points in circle: 15709443
Total points: 20000000
PI: 3.1418886000e+000
Iteration: 48
Points in circle: 15707079
Total points: 20000000
PI: 3.1414158000e+000
Iteration: 49
Points in circle: 15707642
Total points: 20000000
PI: 3.1415284000e+000
Iteration: 50
Points in circle: 15706250
Total points: 20000000
PI: 3.1412500000e+000
Points in circle overall: 15706250
Total points overall: 20000000
PI: 3.1412500000e+000
Percent Error: -1.0907002523e-002%
printf
andstd::cout
? \$\endgroup\$