Skip to content

Instantly share code, notes, and snippets.

@kjelloh
Last active March 12, 2017 18:23
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 kjelloh/204121dd4ec036b7a62d28da78628fcc to your computer and use it in GitHub Desktop.
Save kjelloh/204121dd4ec036b7a62d28da78628fcc to your computer and use it in GitHub Desktop.
An Pi estimation example using std::generate_n
//
// Created by Kjell-Olov Högdahl on 2017-03-08.
// This work is licensed under
// Creative Commons Attribution 4.0 International License.
// https://creativecommons.org/licenses/by/4.0/
//
#include <iostream>
#include <cmath> // std::pow
#include <random> // random_device, std::mt19937, uniform_int_distribution
const auto PI_REFERENCE = 3.14159265359;
struct Fixture {double radius; long point_count;};
struct PiEstimateRecord {
Fixture fixture;
double pi_estimate;
double deviation(const double pi_reference) const {
return std::abs(pi_estimate-pi_reference);
}
bool operator<(const PiEstimateRecord& other) const {
return std::abs(pi_estimate - PI_REFERENCE)
< std::abs(other.pi_estimate - PI_REFERENCE);
}
};
using PiEstimateRecords = std::vector<PiEstimateRecord>;
void print(const PiEstimateRecord& pi_estimate_record) {
std::cout
<< '\n'
<< "PI Estimate"
<< "(radius:" << pi_estimate_record.fixture.radius
<< ",point count:" << pi_estimate_record.fixture.point_count
<< ") = " << pi_estimate_record.pi_estimate
<< " diff from " << PI_REFERENCE
<< " = " << pi_estimate_record.deviation(PI_REFERENCE);
}
void print(const PiEstimateRecords& pi_estimate_records) {
for (auto& pi_estimate_record : pi_estimate_records) {
print(pi_estimate_record);
}
}
namespace pi_estimate_generate_n {
template <int _Cycle>
struct FixtureGenerator {
int seq_no{0};
Fixture operator()() {
// seq_no -> {n,m} using modulo calculus
Fixture result{
pow(10,(seq_no / _Cycle))
,static_cast<long>(pow(10,(seq_no % _Cycle)))};
++seq_no;
return result;
}
};
struct Estimator {
std::mt19937& random_generator;
PiEstimateRecords& result;
const double PI_REFERENCE = 3.14159265359;
// Implement OutputIterator
Estimator& operator*() { return *this;} // value proxy, See operator=
void operator++() {/* ignore ++ */}
// Act as value proxy (See operator*)
void operator=(const Fixture& fixture) {
PiEstimateRecord entry{
fixture
,this->pi_estimation(fixture)};
result.push_back(entry);
print(entry);
};
double pi_estimation(const Fixture& fixture) {
std::uniform_real_distribution<> distribution(
-fixture.radius
,fixture.radius);
const double radius_squared = fixture.radius*fixture.radius;
long points_in_circle_count = 0;
// Count number of random points within circle radius
for (long i=0;i<fixture.point_count;++i) {
// random x,y in square -radius...radious
double x = distribution(random_generator);
double y = distribution(random_generator);
// Use pythagoras to tell point within radius
if ((x*x + y*y) <= radius_squared) {
points_in_circle_count += 1;
}
};
// Estimate Based on Circle Area / Square Area = Pi/4
return
4.0
* static_cast<double>(points_in_circle_count)
/ fixture.point_count;
}
};
template <int N, int M>
PiEstimateRecords do_pi_estimations(std::mt19937& random_generator) {
PiEstimateRecords result;
FixtureGenerator<M+1> fixture_generator;
Estimator pi_estimates{random_generator,result};
std::generate_n(pi_estimates, (N+1)*(M+1), fixture_generator);
return result;
}
}
// See http://www.fluentcpp.com/2017/03/02/the-pi-day-challenge-for-expressive-code-in-c/
int main(int argc, const char * argv[]) {
std::cout << "\nHello from PI Estimator!";
std::random_device random_device;
std::mt19937 random_generator(random_device());
const int N = 9;
const int M = 7;
print(pi_estimate_generate_n::do_pi_estimations<N,M>(random_generator));
std::cout << "\nBye from PI Estimator!";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment