Last active
March 12, 2017 18:23
-
-
Save kjelloh/204121dd4ec036b7a62d28da78628fcc to your computer and use it in GitHub Desktop.
An Pi estimation example using std::generate_n
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
// | |
// 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