Imprecision in Approximating Pi using Monte Carlo Method - c++

Area of the circle = Pi * R^2 and the Area of the square = 4 * R^2.
If we divide the area of the circle by the area of the square we get Pi / 4.
Let's have a square and an inscribed circle in it. We generate points with random coordinates and then count their number in each of the areas.
Then Pi = 4 * (# points in Circle) / (# points in Square).
Here is an attempt at approximating Pi with the above method:
#include <iostream> /* std::cout */
#include <iomanip> /* std::setprecision */
#include <random> /* std::uniform_int_distribution; std::mt19937 */
/* Check if point (x,y) is inside a circle with radius: r, at O(0,0). */
bool isInside (double x, double y, double r) { return (x*x + y*y) <= r*r; }
double approximatePi (double s, int sample_size)
{
std::mt19937 gen; /* Generate random number in [-s/2 : s/2]. */
std::uniform_int_distribution<double> dis(-s/2, s/2);
int count = 0; /* Number of points in the circle. */
for (int i = 0; i < sample_size; ++i)
{
double x = dis(gen);
double y = dis(gen);
if (isInside(x, y, s/2)) /* Radius of inscribed circle = side / 2. */
{
++count;
}
}
/* Pi = 4 * (# points in Circle) / (# points in Square). */
return (double) 4 * count / sample_size;
}
int main()
{
double side = 10.0; /* Square side. */
int sample_size = 10000; /* Number of tries. */
std::cout <<"Pi ~ "<< std::fixed << std::setprecision(6) << approximatePi(side, sample_size) << '\n';
}
Expected result: Pi ~ 3.141592
Actual result: Pi ~ 2.611200
Why am I not getting the expected result? What am I doing wrong?

The effect of std::uniform_int_distribution<double> is undefined behavior, because double is not an integer type.
Change it to std::uniform_real_distribution<double>.

Related

Circle's area using lenght of the side of the square ascribed in the circle / C++

I've written this C++ code which is supposed to compute circles' areas using the length of the side of the square inscribed in the circle. I get no errors but the result isn't right. Any advice?
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
using namespace std;
int main(int argc, const char * argv[]) {
float l, ac, r, area;
cout << "Square's side length: ";
cin >> l;
ac = l * sqrt(2);
r = ac/2;
area = M_PI * pow(2,r);
cout << "Circle's area: "<<area<< endl;
return 0;
}
In computing the area you have to write area = M_PI * pow(r,2);: you just inverted the arguments of the pow function.
The diameter of the circle would be equal to the hypotenuse of the diagonal of the square, so assuming l is side length of the square
float diam = std::sqrt(2.0f * std::pow(l, 2));
float radius = diam / 2.0f;
float area = M_PI * std::pow(radius, 2.0f);

C++ Random Number Generation: Generate cos squared function

The probability distribution of interest is
double x; // range: -pi/2.0 to +pi/2.0
double y = std::pow(std::cos(x), 2.0);
This function can be integrated analytically, however it cannot be inverted. Therefore the usual trick of mapping a uniform distribution to the required probability distribution cannot be performed.
Is there another method which can be used to generate a random variable cos^2(theta) distribution?
It may be possible to find the inverse function numerically, however I do not know of an efficient (memory and computationally) method of doing this.
From Inverse transform sampling: you can generate sample numbers at random from any probability distribution, given its cdf.
Say you want cos2x distribution, from -pi/2 to pi/2. Since integral of cos2x from -pi/2 to pi/2 is pi/2, you need to scale down so that the integral is 1. Thus, the pdf P(x) = (2/pi)cos2x
Next step is calculate cdf from given pdf, which is the pdf's integral. You can use any numerical method to find integral of P(x). Or you can go to Wolfram Alpha and get the answer: cdf is F(x) = (2/pi)(0.5x + 0.25sin2x) + 0.5
Next you need to calcluate F-1(x). Since F(x) is a monotonically increasing function, you can use bisection method (binary search) to find F-1(x) easily. Wolfram Alpha doesn't have this F-1(x) formula though.
Then generate a uniform real number u from 0 to 1. Your custom distribution is F-1(u).
#include <iostream>
#include <cmath>
#include <random>
#include <boost/random/random_device.hpp>
#include <vector>
#include <iomanip>
const double pi = 3.14159265358979323846;
const double LOW = -pi/2;
const double HIGH = pi/2;
double pdf(double x)
{
return cos(x) * cos(x);
}
double cdf(double x) //integral of pdf
{
return (2/pi)*(x/2 + sin(2*x)/4) + 0.5; //from Wolfram Alpha
}
double inverse_cdf(double u)
{ //bisection, not 100% accurate
double low = LOW;
double high = HIGH;
double epsilon = 1e-10; //any small number, e.g. 1e-15
while (high - low > epsilon)
{
double mid = (low + high) / 2;
if (cdf(mid) == u) return mid;
if (cdf(mid) < u) low = mid; else high = mid;
}
return (low + high) / 2;
}
double custom_distribution(std::mt19937& rng)
{
double u = std::uniform_real_distribution<double>(0,1)(rng);
return inverse_cdf(u);
}
int main()
{
std::mt19937 rng{boost::random::random_device{}()};
std::vector<double> xCount(15);
int nSamples = 10000;
double gap = (HIGH-LOW) / xCount.size();
while (nSamples--) xCount[(int)( (custom_distribution(rng) - LOW) / gap )]++;
for (int i = 0; i < xCount.size(); ++i)
{
std::cout << std::setw(2) << i << ":" << xCount[i] << "\t";
for (int bar = xCount[i]/15; bar--; std::cout << '*');
std::cout << "\n";
}
}
sample output:
0:17 *
1:135 *********
2:305 ********************
3:604 ****************************************
4:859 *********************************************************
5:1106 *************************************************************************
6:1256 ***********************************************************************************
7:1353 ******************************************************************************************
8:1271 ************************************************************************************
9:1102 *************************************************************************
10:876 **********************************************************
11:614 ****************************************
12:334 **********************
13:143 *********
14:25 *

How do I end this while loop with a precision of 0.00001 ([C++],[Taylor Series])?

I'm working on this program that approximates a taylor series function. I have to approximate it so that the taylor series function stops approximating the sin function with a precision of .00001. In other words,the absolute value of the last approximation minus the current approximation equals less than or equal to 0.00001. It also approximates each angle from 0 to 360 degrees in 15 degree increments. My logic seems to be correct, but I cannot figure out why i am getting garbage values. Any help is appreciated!
#include <math.h>
#include <iomanip>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <cmath>
double fact(int x){
int F = 1;
for(int i = 1; i <= x; i++){
F*=i;
}
return F;
}
double degreesToRadians(double angle_in_degrees){
double rad = (angle_in_degrees*M_PI)/180;
return rad;
}
using namespace std;
double mySine(double x){
int current =99999;
double comSin=x;
double prev=0;
int counter1 = 3;
int counter2 = 1;
while(current>0.00001){
prev = comSin;
if((counter2 % 2) == 0){
comSin += (pow(x,(counter1))/(fact(counter1)));
}else{
comSin -= (pow(x,(counter1))/(fact(counter1)));
}
current=abs(prev-comSin);
cout<<current<<endl;
counter1+=2;
counter2+=1;
}
return comSin;
}
using namespace std;
int main(){
cout<<"Angle\tSine"<<endl;
for (int i = 0; i<=360; i+=15){
cout<<i<<"\t"<<mySine(degreesToRadians(i));
}
}
Here is an example which illustrates how to go about doing this.
Using the pow function and calculating the factorial at each iteration is very inefficient -- these can often be maintained as running values which are updated alongside the sum during each iteration.
In this case, each iteration's addend is the product of two factors: a power of x and a (reciprocal) factorial. To get from one iteration's power factor to the next iteration's, just multiply by x*x. To get from one iteration's factorial factor to the next iteration's, just multiply by ((2*n+1) + 1) * ((2*n+1) + 2), before incrementing n (the iteration number).
And because these two factors are updated multiplicatively, they do not need to exist as separate running values, they can exists as a single running product. This also helps avoid precision problems -- both the power factor and the factorial can become large very quickly, but the ratio of their values goes to zero relatively gradually and is well-behaved as a running value.
So this example maintains these running values, updated at each iteration:
"sum" (of course)
"prod", the ratio: pow(x, 2n+1) / factorial 2n+1
"tnp1", the value of 2*n+1 (used in the factorial update)
The running update value, "prod" is negated every iteration in order to to factor in the (-1)^n.
I also included the function "XlatedSine". When x is too far away from zero, the sum requires more iterations for an accurate result, which takes longer to run and also can require more precision than our floating-point values can provide. When the magnitude of x goes beyond PI, "XlatedSine" finds another x, close to zero, with an equivalent value for sin(x), then uses this shifted x in a call to MaclaurinSine.
#include <iostream>
#include <iomanip>
// Importing cmath seemed wrong LOL, so define Abs and PI
static double Abs(double x) { return x < 0 ? -x : x; }
const double PI = 3.14159265358979323846;
// Taylor series about x==0 for sin(x):
//
// Sum(n=[0...oo]) { ((-1)^n) * (x^(2*n+1)) / (2*n + 1)! }
//
double MaclaurinSine(double x) {
const double xsq = x*x; // cached constant x squared
int tnp1 = 3; // 2*n+1 | n==1
double prod = xsq*x / 6; // pow(x, 2*n+1) / (2*n+1)! | n==1
double sum = x; // sum after n==0
for(;;) {
prod = -prod;
sum += prod;
static const double MinUpdate = 0.00001; // try zero -- the factorial will always dominate the power of x, eventually
if(Abs(prod) <= MinUpdate) {
return sum;
}
// Update the two factors in prod
prod *= xsq; // add 2 to the power factor's exponent
prod /= (tnp1 + 1) * (tnp1 + 2); // update the factorial factor by two iterations
tnp1 += 2;
}
}
// XlatedSine translates x to an angle close to zero which will produce the equivalent result.
double XlatedSine(double x) {
if(Abs(x) >= PI) {
// Use int casting to do an fmod PI (but symmetric about zero).
// Keep in mind that a really big x could overflow the int,
// however such a large double value will have lost so much precision
// at a sub-PI-sized scale that doing this in a legit fashion
// would also disappoint.
const int p = static_cast<int>(x / PI);
x -= PI * p;
if(p % 2) {
x = -x;
}
}
return MaclaurinSine(x);
}
double DegreesToRadians(double angle_deg) {
return PI / 180 * angle_deg;
}
int main() {
std::cout<<"Angle\tSine\n" << std::setprecision(12);
for(int i = 0; i<=360; i+=15) {
std::cout << i << "\t" << MaclaurinSine(DegreesToRadians(i)) << "\n";
//std::cout << i << "\t" << XlatedSine(DegreesToRadians(i)) << "\n";
}
}

Error with min/max arguments of uniform_real_distribution c++

I have a function to generate a (pseudo) random walk on a square lattice where the walk should not breach the boundaries of this square, full function below:
/**
* #brief Performs a single random walk returning the final distance from the origin
*
* Completes a random walk on a square lattice using the mersenne twister engine based pseudo-random
* number-generator (PRNG). The walk will not breach the boundaries of the square size provided to
* the function. The random walk starts at the origin and ends after some parameterised number of steps.
* Position co-ordinates of the walk for each iteration are sent to an output file.
*
* #param squareSideLength Length of square lattice side
* #param steps Number of steps to compute random walk up to
* #param engine Mersenne Twister engine typedef (used for generating random numbers locally)
* #param distribution Default distribution of random walk
* #param outputFile [Default nullptr] Pointer to file to write co-ordinate data of random walk to
* #return final distance of the particle from the origin
*/
double randomWalkSquareLattice(int squareSideLength, int steps, std::mt19937& engine, std::uniform_real_distribution<double>& distribution, std::ofstream* outputFile = nullptr) {
// store the half-length of the square lattice
const int halfSquareLength = squareSideLength / 2;
// initialise co-ordinates to the origin
double positionX = 0.0;
double positionY = 0.0;
// assign the default distribution to distDefault
std::uniform_real_distribution<double> distDefault = distribution;
// loop over a number of iterations given by the steps parameter
for (int i = 0; i < steps; i++) {
std::cout << positionX << "\t" << positionY << std::endl;
// if the x-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionX >= halfSquareLength) {
double offset = positionX - halfSquareLength;
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(-offset, -1.0);
positionX += distOffset(engine);
}
// else if the x-position of the particle is <= to negative
// half square lattice length then generate incremental random
// number (avoiding breaching the boundary)
else if (positionX <= -halfSquareLength) {
double offset = std::abs(positionX + halfSquareLength);
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(offset, 1.0);
positionX += distOffset(engine);
}
// else (in case where x-position of particle is not touching
// the lattice boundary) generate default random number
else {
positionX += distDefault(engine);
}
// if the y-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionY >= halfSquareLength) {
double offset = positionY - halfSquareLength;
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(-offset, -1.0);
positionY += distOffset(engine);
}
// else if the y-position of the particle is <= to negative
// half square lattice length then generate incremental
// random number (avoiding breaching the boundary)
else if (positionY <= -halfSquareLength) {
double offset = std::abs(positionY + halfSquareLength);
std::cout << std::endl << offset << std::endl;
std::uniform_real_distribution<double> distOffset(offset, 1.0);
positionY += distOffset(engine);
}
// else (in case where y-position of particle is not touching
// the lattice boundary) generate default random number
else {
positionY += distDefault(engine);
}
// if an outputFile is supplied to the function, then write data to it
if (outputFile != nullptr) {
*outputFile << positionX << "\t" << positionY << std::endl;
}
}
// compute final distance of particle from origin
double endDistance = std::sqrt(positionX*positionX + positionY*positionY);
return endDistance;
}
Where the conditionals seen in the method prevent the walk exiting the boundaries. However, when this is called with a sufficient number of steps (so that any one of these conditionals is executed) I get an error saying:
invalid min and max arguments for uniform_real
Note that the dist I send to this function is:
std::uniform_real_distribution<double> dist(-1.0,1.0);
And so (as you can see from the values printed to the terminal) the issue is not that the offset will ever be larger than the max value given to the distOffset in any of the conditional cases.
Is the issue that I cannot give u_r_d a double value of arbitrary precision? Or is something else at play here that I am missing?
Edit: I should add that these are the values used in main():
int main(void) {
std::uniform_real_distribution<double> dist(-1.0, 1.0);
std::random_device randDevice;
std::mt19937 engine(randDevice());
//std::cout << dist(engine) << std::endl;
// Dimensions of Square Lattice
const int squareLength = 100;
// Number of Steps in Random Walk
const int nSteps = 10000;
randomWalkSquareLattice(squareLength, nSteps, engine, dist);
}
uniform_real_distribution(a,b); requires that a ≤ b.
If positionX == halfSquareLength, then,
double offset = positionX - halfSquareLength;
is the same as saying
double offset = positionX - positionX;
and offset will be zero.
This results in
std::uniform_real_distribution<double> distOffset(-0.0, -1.0);
and violates a ≤ b.
Here is the solution I came up with, seems to work for all test cases so far:
/**
* #brief Performs a single random walk returning the final distance from the origin
*
* Completes a random walk on a square lattice using the mersenne twister engine based pseudo-random
* number-generator (PRNG). The walk will not breach the boundaries of the square size provided to
* the function. The random walk starts at the origin and ends after some parameterised number of steps.
* Position co-ordinates of the walk for each iteration are sent to an output file.
*
* #param squareSideLength Length of square lattice side
* #param steps Number of steps to compute random walk up to
* #param engine Mersenne Twister engine typedef (used for generating random numbers locally)
* #param distribution Default distribution of random walk
* #param outputFile [Default nullptr] Pointer to file to write co-ordinate data of random walk to
* #return final distance of the particle from the origin
*/
double randomWalkSquareLattice(int squareSideLength, int steps, std::mt19937& engine, std::uniform_real_distribution<double>& distribution, std::ofstream* outputFile = nullptr) {
// store the half-length of the square lattice
const int halfSquareLength = squareSideLength / 2;
// initialise co-ordinates to the origin
double positionX = 0.0;
double positionY = 0.0;
// assign the default distribution to distDefault
std::uniform_real_distribution<double> distDefault = distribution;
std::uniform_real_distribution<double> distBound(0.0, 1.0);
double oS;
// loop over a number of iterations given by the steps parameter
for (int i = 0; i < steps; i++) {
//std::cout << positionX << "\t" << positionY << std::endl;
positionX += distDefault(engine);
positionY += distDefault(engine);
// if the x-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionX >= halfSquareLength) {
oS = distBound(engine);
double offset = positionX - halfSquareLength;
double desiredOffset = -(oS + offset);
if (desiredOffset < -1.0) {
double offsetFromNegUnity = desiredOffset + 1.0;
desiredOffset -= offsetFromNegUnity;
}
positionX += desiredOffset;
}
// else if the x-position of the particle is <= to negative
// half square lattice length then generate incremental random
// number (avoiding breaching the boundary)
else if (positionX <= -halfSquareLength) {
oS = distBound(engine);
double offset = std::abs(positionX + halfSquareLength);
double desiredOffset = offset+oS;
if (desiredOffset > 1.0) {
double offsetFromUnity = desiredOffset - 1.0;
desiredOffset -= offsetFromUnity;
}
positionX += desiredOffset;
}
// if the y-position of the particle is >= to positive
// half square lattice length then generate decremental
// random number (avoiding breaching the boundary)
if (positionY >= halfSquareLength) {
oS = distBound(engine);
double offset = positionY - halfSquareLength;
double desiredOffset = -(offset+oS);
if (desiredOffset < -1.0) {
double offsetFromNegUnity = desiredOffset + 1.0;
desiredOffset -= offsetFromNegUnity;
}
positionY += desiredOffset;
}
// else if the y-position of the particle is <= to negative
// half square lattice length then generate incremental
// random number (avoiding breaching the boundary)
else if (positionY <= -halfSquareLength) {
oS = distBound(engine);
double offset = std::abs(positionY + halfSquareLength);
double desiredOffset = offset+oS;
if (desiredOffset > 1.0) {
double offsetFromUnity = desiredOffset - 1.0;
desiredOffset -= offsetFromUnity;
}
positionY += desiredOffset;
}
// if an outputFile is supplied to the function, then write data to it
if (outputFile != nullptr) {
*outputFile << positionX << "\t" << positionY << std::endl;
}
}
// compute final distance of particle from origin
double endDistance = std::sqrt(positionX*positionX + positionY*positionY);
return endDistance;
}
Here, an offset was generated randomly on the interval (0,1) and the difference from the boundary by which a x or y position breached was added to this offset to create a double value which would have a minimum of this breaching difference and (after an additional nested conditional check) a maximum of 1.0 (or -1.0 for opposite boundary).

Memory Overflow? std::badalloc

I have a program that solves generally for 1D brownian motion using an Euler's Method.
Being a stochastic process, I want to average it over many particles. But I find that as I ramp up the number of particles, it overloads and i get the std::badalloc error, which I understand is a memory error.
Here is my full code
#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <ctime>
using namespace std;
// Box-Muller Method to generate gaussian numbers
double generateGaussianNoise(double mu, double sigma) {
const double epsilon = std::numeric_limits<double>::min();
const double tau = 2.0 * 3.14159265358979323846;
static double z0, z1;
static bool generate;
generate = !generate;
if (!generate) return z1 * sigma + mu;
double u1, u2;
do {
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
z0 = sqrt(-2.0 * log(u1)) * cos(tau * u2);
z1 = sqrt(-2.0 * log(u1)) * sin(tau * u2);
return z0 * sigma + mu;
}
int main() {
// Initialize Variables
double gg; // Gaussian Number Picked from distribution
// Integrator
double t0 = 0; // Setting the Time Window
double tf = 10;
double n = 5000; // Number of Steps
double h = (tf - t0) / n; // Time Step Size
// Set Constants
const double pii = atan(1) * 4; // pi
const double eta = 1; // viscous constant
const double m = 1; // mass
const double aa = 1; // radius
const double Temp = 30; // Temperature in Kelvins
const double KB = 1; // Boltzmann Constant
const double alpha = (6 * pii * eta * aa);
// More Constants
const double mu = 0; // Gaussian Mean
const double sigma = 1; // Gaussian Std Deviation
const double ng = n; // No. of pts to generate for Gauss distribution
const double npart = 1000; // No. of Particles
// Initial Conditions
double x0 = 0;
double y0 = 0;
double t = t0;
// Vectors
vector<double> storX; // Vector that keeps displacement values
vector<double> storY; // Vector that keeps velocity values
vector<double> storT; // Vector to store time
vector<double> storeGaussian; // Vector to store Gaussian numbers generated
vector<double> holder; // Placeholder Vector for calculation operations
vector<double> mainstore; // Vector that holds the final value desired
storT.push_back(t0);
// Prepares mainstore
for (int z = 0; z < (n+1); z++) {
mainstore.push_back(0);
}
for (int NN = 0; NN < npart; NN++) {
holder.clear();
storX.clear();
storY.clear();
storT.clear();
storT.push_back(0);
// Prepares holder
for (int z = 0; z < (n+1); z++) {
holder.push_back(0);
storX.push_back(0);
storY.push_back(0);
}
// Gaussian Generator
srand(time(NULL));
for (double iiii = 0; iiii < ng; iiii++) {
gg = generateGaussianNoise(0, 1); // generateGaussianNoise(mu,sigma)
storeGaussian.push_back(gg);
}
// Solver
for (int ii = 0; ii < n; ii++) {
storY[ii + 1] =
storY[ii] - (alpha / m) * storY[ii] * h +
(sqrt(2 * alpha * KB * Temp) / m) * sqrt(h) * storeGaussian[ii];
storX[ii + 1] = storX[ii] + storY[ii] * h;
holder[ii + 1] =
pow(storX[ii + 1], 2); // Finds the displacement squared
t = t + h;
storT.push_back(t);
}
// Updates the Main Storage
for (int z = 0; z < storX.size(); z++) {
mainstore[z] = mainstore[z] + holder[z];
}
}
// Average over the number of particles
for (int z = 0; z < storX.size(); z++) {
mainstore[z] = mainstore[z] / (npart);
}
// Outputs the data
ofstream fout("LangevinEulerTest.txt");
for (int jj = 0; jj < storX.size(); jj++) {
fout << storT[jj] << '\t' << mainstore[jj] << '\t' << storX[jj] << endl;
}
return 0;
}
As you can see, npart is the variable that I change to vary the number of particles. But after each iteration, I do clear my storage vectors like storX,storY... So on paper, the number of particles should not affect memory? I am only just calling the compiler to repeat many more times, and add onto the main storage vector mainstore. I am running my code on a computer with 4GB ram.
Would greatly appreciate it if anyone could point out my errors in logic or suggest improvements.
Edit: Currently the number of particles is set to npart = 1000.
So when I try to ramp it up to like npart = 20000 or npart = 50000, it gives me memory errors.
Edit2 I've edited the code to allocate an extra index to each of the storage vectors. But it does not seem to fix the memory overflow
There is an out of bounds exception in the solver part. storY has size n and you access ii+1 where i goes up to n-1. So for your code provided. storY has size 5000. It is allowed to access with indices between 0 and 4999 (including) but you try to access with index 5000. The same for storX, holder and mainstore.
Also, storeGaussian does not get cleared before adding new variables. It grows by n for each npart loop. You access only the first n values of it in the solver part anyway.
Please note, that vector::clear removes all elements from the vector, but does not necessarily change the vector's capacity (i.e. it's storage array), see the documentation.
This won't cause the problem here, because you'll reuse the same array in the next runs, but it's something to be aware when using vectors.