Created
March 5, 2017 22:46
-
-
Save elbeno/aace93b23510450ef95c0cb45120cf37 to your computer and use it in GitHub Desktop.
Expressive code to (poorly) approximate pi
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
// 2017 Pi Day challenge: | |
// http://www.fluentcpp.com/2017/03/02/the-pi-day-challenge-for-expressive-code-in-c/ | |
#include <algorithm> | |
#include <array> | |
#include <cmath> | |
#include <functional> | |
#include <iomanip> | |
#include <iostream> | |
#include <random> | |
#include <utility> | |
using namespace std; | |
// a coordinate is a pair of doubles | |
using coord_t = pair<double, double>; | |
// run a function n times, and count the number of values produced that satisfy | |
// a predicate | |
template <typename F, typename Size, typename Pred> | |
auto count_if_generate_n(F&& f, Size n, Pred&& p) | |
{ | |
Size count{}; | |
while (n-- > 0) { | |
if (p(f())) ++count; | |
} | |
return count; | |
} | |
// initialize the RNG | |
decltype(auto) init_RNG() | |
{ | |
array<int, mt19937::state_size> seed_data; | |
random_device rd; | |
generate_n(seed_data.data(), seed_data.size(), ref(rd)); | |
seed_seq seq(begin(seed_data), end(seed_data)); | |
static mt19937 gen(seq); | |
return (gen); | |
} | |
// the value of pi we're using as a yardstick | |
const double pi = 3.14159265359; | |
int main() | |
{ | |
// initialize RNG, pad output with spaces | |
auto& gen = init_RNG(); | |
cout.fill(' '); | |
for (auto r_power = 0; r_power < 9; ++r_power) | |
{ | |
for (auto n_power = 0; n_power < 7; ++n_power) | |
{ | |
// radius & number of iterations | |
const auto r = pow(10.0, r_power); | |
const auto n = static_cast<int>(pow(10, n_power)); | |
// coordinates are generated in the square of size 2r | |
auto d = uniform_real_distribution<double>(-r, r); | |
// count how many random samples fall within a circle | |
const auto hits = count_if_generate_n( | |
[&] () -> coord_t { return {d(gen), d(gen)}; }, | |
n, | |
[&] (const auto& c) { return hypot(c.first, c.second) <= r; }); | |
// not-a-very-good approximation to pi | |
double pi_approx = hits * 4 / static_cast<double>(n); | |
cout << setw(12) << abs(pi_approx - pi) << ' '; | |
} | |
cout << '\n'; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment