The other day I learnt a method to approximate Pi if you have a random number generator for the range [0,1]. Consider a unit circle centred on (0,0) in 2D coordinates. Then one quarter of the area of the circle lies in the quadrant formed by x and y in range [0,1]. The area of the quarter circle is Pi * R^2/4, and here, R = 1 (it’s a unit circle). So we can generate a bunch of random 2D points, calculate the ratio between those that fall inside the circle and those in the outer unit square, then multiply by 4 to approximate Pi.
That sounds like a neat test case for the C++11 random number generators, so I thought I’d try it out. It turns out to work pretty well, if you’re prepared to use a sufficiently large number of random values.
double approxPi( size_t points ) { std::random_device rand_device; // mersenne_twister_engine is a random number engine // based on Mersenne Twister algorithm. std::mt19937 generator( rand_device() ); // We want random values uniformly distributed in [0,1] std::uniform_real_distribution<> unif_zero_one(0, 1); size_t points_inside{0}; for (int i = 0; i < points; ++i ) { auto x = unif_zero_one( generator ); auto y = unif_zero_one( generator ); double d = std::sqrt( x*x + y*y ); if ( d <= 1.0 ) ++points_inside; } return 4.0 * (static_cast<double>(points_inside) / static_cast<double>(points)); } } void testApproximatePi() { SHOULD_BE_APPROX( 3.14159, 0.3, approxPi( 100 ) ); SHOULD_BE_APPROX( 3.14159, 0.1, approxPi( 1000 ) ); SHOULD_BE_APPROX( 3.14159, 0.01, approxPi( 100000 ) ); SHOULD_BE_APPROX( 3.14159, 0.001, approxPi( 10000000 ) ); std::cout << "\n"; }
A typical run gives reasonable approximations once you get over 100,000 points: