Skip to content

Instantly share code, notes, and snippets.

@kjelloh
Created March 12, 2017 17:56
Show Gist options
  • Save kjelloh/6b08835e362bcc55ae781797c472f91d to your computer and use it in GitHub Desktop.
Save kjelloh/6b08835e362bcc55ae781797c472f91d to your computer and use it in GitHub Desktop.
A Pi Estimation example using std::transform
//
// 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