Skip to content

Instantly share code, notes, and snippets.

@jabney
Last active January 22, 2021 23:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jabney/7656e3a313e57b6955d89ebc0fbeb1c3 to your computer and use it in GitHub Desktop.
Save jabney/7656e3a313e57b6955d89ebc0fbeb1c3 to your computer and use it in GitHub Desktop.
Calculate PI using Leibniz algorithm spread across multiple threads
#include <algorithm>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <thread>
#include <vector>
using namespace std;
/**
* Leibniz formula for π: 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...
*/
double calculate_pi(uint64_t const start, uint64_t const end) {
double sum = 0;
for (uint64_t i = start; i < end; i++) {
int const sign = i % 2 ? -1 : 1;
double const term = 2 * i + 1;
sum += sign / term;
}
return 4 * sum;
}
/**
* Subdivide PI calculations among multiple threads.
*/
double calculate_pi_multithreaded(uint64_t const iterations,
size_t const num_threads = thread::hardware_concurrency()) {
vector<thread *> threads(num_threads);
uint64_t const chunk = iterations / num_threads;
vector<double> sums(num_threads);
for (size_t i = 0; i < num_threads; i++) {
threads[i] = new thread([=, &sums]() {
auto const result = calculate_pi(i * chunk, (i + 1) * chunk);
sums[i] = result;
});
}
for (thread * t : threads) {
t->join();
delete t;
}
// Sort high-to-low for more precise (and consistent) summing of fractions.
sort(sums.begin(), sums.end(), [](double a, double b) { return b < a; });
return accumulate(sums.begin(), sums.end(), 0.0);
}
/**
* Execute a function and return the elapsed time.
*/
double measure_time(function<void(void)> const fn) {
auto t1 = chrono::high_resolution_clock::now();
fn();
auto t2 = chrono::high_resolution_clock::now();
auto delta = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
return delta.count();
}
/**
*
*/
int main() {
uint64_t const iterations = 1e10;
cout << setprecision(1) << scientific;
cout << "Calculating PI (Leibniz, " << (double)iterations << " iterations) " << endl;
double pi;
auto exec_time = measure_time([&pi]() {
//
pi = calculate_pi_multithreaded(iterations);
});
cout << fixed << setprecision(17) << pi << endl;
cout << "Time to run: " << setprecision(2) << exec_time << " seconds" << endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment