Last active
March 15, 2017 00:07
-
-
Save arnemertz/5c2a049c2260c9539f43534aec1fcbaa to your computer and use it in GitHub Desktop.
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 <iostream> | |
#include <vector> | |
#include <cmath> | |
#include <algorithm> | |
#include <random> | |
#include <cassert> | |
struct coordinates { | |
double x; | |
double y; | |
}; | |
struct bounding_box { | |
coordinates min; | |
coordinates max; | |
}; | |
class random_point_generator { | |
static inline std::mt19937 gen{std::random_device{}()}; | |
std::uniform_real_distribution<double> dist_x; | |
std::uniform_real_distribution<double> dist_y; | |
public: | |
explicit random_point_generator(bounding_box box) | |
: dist_x{box.min.x, box.max.x} | |
, dist_y{box.min.y, box.max.y} | |
{} | |
coordinates operator()() { | |
return {dist_x(gen), dist_y(gen)}; | |
} | |
}; | |
auto generate_random_points(std::size_t points_total, bounding_box box) { | |
std::vector<coordinates> points(points_total, {0,0}); | |
std::generate(begin(points), end(points), random_point_generator{box}); | |
return points; | |
} | |
bounding_box centered_quadratic_bounding_box(double max_coordinate) { | |
assert(max_coordinate > 0.0); | |
return {{-max_coordinate, -max_coordinate}, {max_coordinate, max_coordinate}}; | |
} | |
auto is_in_centered_circle(double radius) { | |
auto predicate = [=](coordinates point){ | |
return hypot(point.x, point.y) < radius; | |
}; | |
return predicate; | |
} | |
double approximate_pi(std::size_t points_count_total, double radius){ | |
auto random_points = generate_random_points(points_count_total, centered_quadratic_bounding_box(radius)); | |
auto points_count_in_circle = std::count_if(begin(random_points), end(random_points), is_in_centered_circle(radius)); | |
auto approximated_pi = 4.0 * static_cast<double>(points_count_in_circle) / static_cast<double>(points_count_total); | |
return approximated_pi; | |
} | |
double difference_to_pi(double pi_candidate) { | |
const static double pi = 3.14159265359; | |
return std::abs(pi - pi_candidate); | |
} | |
int main() { | |
for (auto radius_exp : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) { | |
for (auto point_count_exp : {0, 1, 2, 3, 4, 5, 6, 7}) { | |
double radius = std::pow(10, radius_exp); | |
auto point_count = static_cast<std::size_t>(std::pow(10, point_count_exp)); | |
auto approximated_pi = approximate_pi(point_count, radius); | |
auto difference = difference_to_pi(approximated_pi); | |
std::cout << difference << '\t'; | |
} | |
std::cout << '\n'; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That trick with the initializer list in the for loop is brilliant! (I'm talking about
for (auto radius_exp : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
)I can just imagine some of the old-school C++ engineers cringing when I show this to them. Thank you!