From a11b7c32253acf1da8090ea60d0e27e80dda24eb Mon Sep 17 00:00:00 2001 From: Zhihua Lai Date: Mon, 23 Feb 2026 13:08:50 +0000 Subject: [PATCH 1/2] Add Pi Monte Carlo Parallel Simulation --- README.md | 1 + pi-monte-carlo/Makefile | 30 ++++++++++++++++++++ pi-monte-carlo/main.cpp | 61 +++++++++++++++++++++++++++++++++++++++++ pi-monte-carlo/tests.sh | 12 ++++++++ 4 files changed, 104 insertions(+) create mode 100644 pi-monte-carlo/Makefile create mode 100644 pi-monte-carlo/main.cpp create mode 100755 pi-monte-carlo/tests.sh diff --git a/README.md b/README.md index 082497b..7033920 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Examples include (and will expand to): * Encoding * [rot47](./rot47/) * [prefix-sum](./prefix-sum/) + * [pi-monte-carlo](./pi-monte-carlo/) * Data Structures * [map-with-unknown-key](./map-with-unknown-key/) * OOP diff --git a/pi-monte-carlo/Makefile b/pi-monte-carlo/Makefile new file mode 100644 index 0000000..172da2f --- /dev/null +++ b/pi-monte-carlo/Makefile @@ -0,0 +1,30 @@ +# pull in shared compiler settings +include ../common.mk + +# per-example flags +# CXXFLAGS += -pthread + +## get it from the folder name +TARGET := $(notdir $(CURDIR)) +SRCS := $(wildcard *.cpp) +OBJS := $(SRCS:.cpp=.o) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CXX) $(CXXFLAGS) -o $@ $^ + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +run: $(TARGET) + ./$(TARGET) $(ARGS) + +clean: + rm -f $(OBJS) $(TARGET) + +# Delegates to top-level Makefile +check-format: + $(MAKE) -f ../Makefile check-format DIR=$(CURDIR) + +.PHONY: all clean run check-format diff --git a/pi-monte-carlo/main.cpp b/pi-monte-carlo/main.cpp new file mode 100644 index 0000000..534847f --- /dev/null +++ b/pi-monte-carlo/main.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include + +static std::uint64_t +count_hits(std::uint64_t n, std::uint64_t seed) +{ + std::mt19937_64 rng(seed); + std::uniform_real_distribution dist(0.0, 1.0); + + std::uint64_t hits = 0; + for (std::uint64_t i = 0; i < n; ++i) { + const double x = dist(rng); + const double y = dist(rng); + if (x * x + y * y <= 1.0) + ++hits; + } + return hits; +} + +int +main(int argc, char* argv[]) +{ + int threads = 2; + std::uint64_t n = 1'000'000; + + if (argc > 1) + threads = std::max(1, std::atoi(argv[1])); + if (argc > 2) + n = std::max(1, std::strtoull(argv[2], nullptr, 10)); + + const std::uint64_t base = n / threads; + const std::uint64_t rem = n % threads; + + std::vector pool; + std::vector hits(threads, 0); + + // a single nondeterministic seed source; each thread gets a different seed + std::random_device rd; + const std::uint64_t master_seed = (static_cast(rd()) << 32) ^ static_cast(rd()); + + for (int i = 0; i < threads; ++i) { + const std::uint64_t points = base + (static_cast(i) < rem ? 1 : 0); + const std::uint64_t seed = master_seed + 0x9e3779b97f4a7c15ULL * static_cast(i + 1); + + pool.emplace_back([&, i, points, seed] { hits[i] = count_hits(points, seed); }); + } + + for (auto& t : pool) + t.join(); + + const std::uint64_t total_hits = std::accumulate(hits.begin(), hits.end(), std::uint64_t{0}); + const long double pi = 4.0 * static_cast(total_hits) / static_cast(n); + + std::cout << pi << "\n"; + return 0; +} \ No newline at end of file diff --git a/pi-monte-carlo/tests.sh b/pi-monte-carlo/tests.sh new file mode 100755 index 0000000..337fb84 --- /dev/null +++ b/pi-monte-carlo/tests.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -ex + +./rot47 + +helloworld=$(./rot47 'w6==@ (@C=5P') + +if [ "$helloworld" != "Hello World!" ]; then + echo "Test failed: expected 'Hello World!' but got '$helloworld'" + exit 1 +fi From 196a5044e48be995928dbe0a4496a79cdd0e07b6 Mon Sep 17 00:00:00 2001 From: Zhihua Lai Date: Mon, 23 Feb 2026 13:10:28 +0000 Subject: [PATCH 2/2] Fix tests --- pi-monte-carlo/tests.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pi-monte-carlo/tests.sh b/pi-monte-carlo/tests.sh index 337fb84..24e28b6 100755 --- a/pi-monte-carlo/tests.sh +++ b/pi-monte-carlo/tests.sh @@ -2,11 +2,14 @@ set -ex -./rot47 +# Run the tests +pi=$(./pi-monte-carlo) -helloworld=$(./rot47 'w6==@ (@C=5P') - -if [ "$helloworld" != "Hello World!" ]; then - echo "Test failed: expected 'Hello World!' but got '$helloworld'" +# Check that the result is within a reasonable range +if (( $(echo "$pi < 3.0" | bc -l) )) || + (( $(echo "$pi > 3.2" | bc -l) )); then + echo "Test failed: pi is out of range: $pi" exit 1 +else + echo "Test passed: pi is within range: $pi" fi