Created
March 12, 2017 17:56
-
-
Save kjelloh/6b08835e362bcc55ae781797c472f91d to your computer and use it in GitHub Desktop.
A Pi Estimation example using std::transform
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_transform { | |
template <int _Cycle> | |
struct FixtureGenerator { | |
int seq_no; | |
Fixture operator*() { | |
// seq_no -> {n,m} using modulo calculus | |
Fixture result{ | |
pow(10,(seq_no / _Cycle)) | |
,static_cast<long>(pow(10,(seq_no % _Cycle))) | |
}; | |
return result; | |
} | |
void operator++() {++seq_no;} | |
bool operator!=(const FixtureGenerator& other) { | |
return (seq_no != other.seq_no); | |
} | |
}; | |
template <int _Cycle2, int _Cycle1> | |
struct Fixtures { | |
auto begin() {return FixtureGenerator<_Cycle1>{0};} | |
auto end() {return FixtureGenerator<_Cycle1>{_Cycle2*_Cycle1};} | |
}; | |
struct estimate_pi { | |
std::mt19937& random_generator; | |
PiEstimateRecord operator()(const Fixture& fixture) { | |
PiEstimateRecord result{ | |
fixture | |
,this->pi_estimation(fixture) | |
}; | |
print(result); | |
return result; | |
}; | |
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; | |
Fixtures<N+1,M+1> fixtures; | |
std::transform( | |
fixtures.begin() | |
,fixtures.end() | |
,std::back_inserter(result) | |
,estimate_pi{random_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_transform::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