Skip to content

Commit 13c005d

Browse files
Merge pull request #19 from DoctorLai/pi
Add Pi Monte Carlo Parallel Simulation
2 parents 531cebe + 196a504 commit 13c005d

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Examples include (and will expand to):
3535
* Encoding
3636
* [rot47](./rot47/)
3737
* [prefix-sum](./prefix-sum/)
38+
* [pi-monte-carlo](./pi-monte-carlo/)
3839
* Data Structures
3940
* [map-with-unknown-key](./map-with-unknown-key/)
4041
* OOP

pi-monte-carlo/Makefile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# pull in shared compiler settings
2+
include ../common.mk
3+
4+
# per-example flags
5+
# CXXFLAGS += -pthread
6+
7+
## get it from the folder name
8+
TARGET := $(notdir $(CURDIR))
9+
SRCS := $(wildcard *.cpp)
10+
OBJS := $(SRCS:.cpp=.o)
11+
12+
all: $(TARGET)
13+
14+
$(TARGET): $(OBJS)
15+
$(CXX) $(CXXFLAGS) -o $@ $^
16+
17+
%.o: %.cpp
18+
$(CXX) $(CXXFLAGS) -c $< -o $@
19+
20+
run: $(TARGET)
21+
./$(TARGET) $(ARGS)
22+
23+
clean:
24+
rm -f $(OBJS) $(TARGET)
25+
26+
# Delegates to top-level Makefile
27+
check-format:
28+
$(MAKE) -f ../Makefile check-format DIR=$(CURDIR)
29+
30+
.PHONY: all clean run check-format

pi-monte-carlo/main.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include <algorithm>
2+
#include <cstdint>
3+
#include <iostream>
4+
#include <numeric>
5+
#include <random>
6+
#include <thread>
7+
#include <vector>
8+
9+
static std::uint64_t
10+
count_hits(std::uint64_t n, std::uint64_t seed)
11+
{
12+
std::mt19937_64 rng(seed);
13+
std::uniform_real_distribution<double> dist(0.0, 1.0);
14+
15+
std::uint64_t hits = 0;
16+
for (std::uint64_t i = 0; i < n; ++i) {
17+
const double x = dist(rng);
18+
const double y = dist(rng);
19+
if (x * x + y * y <= 1.0)
20+
++hits;
21+
}
22+
return hits;
23+
}
24+
25+
int
26+
main(int argc, char* argv[])
27+
{
28+
int threads = 2;
29+
std::uint64_t n = 1'000'000;
30+
31+
if (argc > 1)
32+
threads = std::max(1, std::atoi(argv[1]));
33+
if (argc > 2)
34+
n = std::max<std::uint64_t>(1, std::strtoull(argv[2], nullptr, 10));
35+
36+
const std::uint64_t base = n / threads;
37+
const std::uint64_t rem = n % threads;
38+
39+
std::vector<std::thread> pool;
40+
std::vector<std::uint64_t> hits(threads, 0);
41+
42+
// a single nondeterministic seed source; each thread gets a different seed
43+
std::random_device rd;
44+
const std::uint64_t master_seed = (static_cast<std::uint64_t>(rd()) << 32) ^ static_cast<std::uint64_t>(rd());
45+
46+
for (int i = 0; i < threads; ++i) {
47+
const std::uint64_t points = base + (static_cast<std::uint64_t>(i) < rem ? 1 : 0);
48+
const std::uint64_t seed = master_seed + 0x9e3779b97f4a7c15ULL * static_cast<std::uint64_t>(i + 1);
49+
50+
pool.emplace_back([&, i, points, seed] { hits[i] = count_hits(points, seed); });
51+
}
52+
53+
for (auto& t : pool)
54+
t.join();
55+
56+
const std::uint64_t total_hits = std::accumulate(hits.begin(), hits.end(), std::uint64_t{0});
57+
const long double pi = 4.0 * static_cast<long double>(total_hits) / static_cast<long double>(n);
58+
59+
std::cout << pi << "\n";
60+
return 0;
61+
}

pi-monte-carlo/tests.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
set -ex
4+
5+
# Run the tests
6+
pi=$(./pi-monte-carlo)
7+
8+
# Check that the result is within a reasonable range
9+
if (( $(echo "$pi < 3.0" | bc -l) )) ||
10+
(( $(echo "$pi > 3.2" | bc -l) )); then
11+
echo "Test failed: pi is out of range: $pi"
12+
exit 1
13+
else
14+
echo "Test passed: pi is within range: $pi"
15+
fi

0 commit comments

Comments
 (0)