Last active
January 22, 2021 23:36
-
-
Save jabney/7656e3a313e57b6955d89ebc0fbeb1c3 to your computer and use it in GitHub Desktop.
Calculate PI using Leibniz algorithm spread across multiple threads
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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