Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Examples include (and will expand to):
* RAII and ownership patterns
* Parallelism
* [parallel-transform](./parallel-transform/)
* [parallel-integral-pi](./parallel-integral-pi/)
* Performance‑oriented C++ idioms
* STL and ranges:
* [ranges-find-in-vector-string](./ranges-find-in-vector-string/)
Expand Down
30 changes: 30 additions & 0 deletions parallel-integral-pi/Makefile
Original file line number Diff line number Diff line change
@@ -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
68 changes: 68 additions & 0 deletions parallel-integral-pi/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>

double
f(double x)
{
return 4.0 / (1.0 + x * x);
}

int
main(int argc, char* argv[])
{
long long iterations = 1000000;
if (argc > 1) {
iterations = std::atoll(argv[1]);
}
int threads = 10;
if (argc > 2) {
threads = std::atoi(argv[2]);
}

if (iterations <= 0 || threads <= 0) {
std::cerr << "iterations and threads must be positive integers\n";
return 1;
}

const double h = 1.0 / static_cast<double>(iterations);
const long long interior_points = iterations - 1;
const int worker_count = static_cast<int>(std::min<long long>(threads, iterations));
const long long points_per_thread = interior_points / worker_count;
const long long remainder = interior_points % worker_count;

std::vector<std::thread> thread_pool;
thread_pool.reserve(worker_count);
std::vector<double> partial_sums(worker_count, 0.0);

for (int t = 0; t < worker_count; ++t) {
thread_pool.emplace_back([&, t]() {
const long long thread_index = t;
const long long start = 1 + thread_index * points_per_thread + std::min(thread_index, remainder);
const long long end = start + points_per_thread + (thread_index < remainder ? 1 : 0);

double local_sum = 0.0;
for (long long i = start; i < end; ++i) {
const double x = h * static_cast<double>(i);
local_sum += 2.0 * f(x);
}
partial_sums[t] = local_sum;
});
}

for (auto& thread : thread_pool) {
thread.join();
}

// T_n = (h / 2) * (f(0) + f(1) + 2 * sum of interior points).
double sum = f(0.0) + f(1.0);
for (const double partial_sum : partial_sums) {
sum += partial_sum;
}

const double pi = (h / 2.0) * sum;
std::cout.precision(15);
std::cout << "pi = " << pi << '\n';
}
25 changes: 25 additions & 0 deletions parallel-integral-pi/tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash

set -euo pipefail

output=$(./parallel-integral-pi 100000 6)
pi=${output#pi = }

if ! awk -v pi="$pi" 'BEGIN {
expected = atan2(0, -1)
error = pi - expected
if (error < 0) {
error = -error
}
exit !(error < 0.000000001)
}'; then
echo "Test failed: inaccurate approximation: $pi"
exit 1
fi

if ./parallel-integral-pi 0 2 >/dev/null 2>&1; then
echo "Test failed: zero iterations should be rejected"
exit 1
fi

echo "Test passed: pi = $pi"
Loading