Why Is My Java Monte Carlo Simulation Not Approximating Pi Accurately?

In summary, the MonteCarlo class calculates the area of a circle by multiplying the radius by 2. The nextRainDrop_x() method checks to see if the given x value falls within the bounds of the circle. If not, it calculates the amount of decimal places to place in the amount of the x value and saves it in lowestXvalue and highestXvalue.
  • #1
Indigo_Blue
5
0

Homework Statement


There is a square and a circle is inscribed inside. Simulate an experiment where raindrops drop on this surface. Some raindrops can drop in or on the border of the circle. Some can drop outside the circle. The area of the square divided by the area of the circle gives you pi. If we manipulate this equation using the amount of times a raindrop drops into or outside the circle, we can approximate pi. The calculated value of pi is supposed to become more accurate as we run the simulation more. However, I am always getting these values:
4.695652173913044
4.333333333333333
4.321198252548367
4.378718056137411
4.337363058811759
The number does not seem to get closer to pi even if I increase the amount of times the loop iterates. I cannot find the error that would make this number off from pi.

Homework Equations


(x – h)^2 + (y – k)^2 = r^2 is the equation of a circle.

The Attempt at a Solution


There are two classes in my code.
Mentor note: I added code tags to make your code more readable. In future posts involving Java code, you should add code tags, like so:
[code=java]<Your java code
.
.
.
[/code]
Main class
Java:
public class Main {

    public static void main(String[] args) {
       MonteCarlo circle=new MonteCarlo(5,3,2);
   
       int cirCount=0; int sqrCount=0; double area=(Math.pow(2*circle.r,2));
       for(int x=0;x<100;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
           cirCount++;
           else
           sqrCount++;
       
       }
        System.out.println((cirCount*(area))/(sqrCount*circle.r*circle.r));
        cirCount=0; sqrCount=0;
        for(int x=0;x<1000;x++)
        {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
           cirCount++;
           else
           sqrCount++;
       
       }
        System.out.println(cirCount*(area)/(sqrCount*(circle.r*circle.r)));
        cirCount=0; sqrCount=0;
        for(int x=0;x<10000;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
              cirCount++;
           else
              sqrCount++;       
       }
       System.out.println(cirCount*(area)/(sqrCount*circle.r*circle.r));
       cirCount=0; sqrCount=0;
       for(int x=0;x<100000;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
              cirCount++;
           else
              sqrCount++;       
       }
       System.out.println(cirCount*(area)/(sqrCount*circle.r*circle.r));
       cirCount=0; sqrCount=0;
       for(int x=0;x<1000000;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
              cirCount++;
           else
              sqrCount++;       
       }
       System.out.println((cirCount*(area))/(sqrCount*circle.r*circle.r));    
    }
}

MonteCarlo class
import java.util.*;
public class MonteCarlo{
 
    public double h;
    public double k;
    public double r;
    private Random rndm= new Random();
 
    public  MonteCarlo(double x,double y, double z)
    {
        h=x; k=y; r=z;
    }
 
    public double nextRainDrop_x()
    {
        int lowestXvalue;
        int highestXvalue;
        if(h != (int)h){
           double amountOfDecimalPlaces=Math.pow(10,String.valueOf(h).split("\\.")[1].length());
           int newh=(int)(h*amountOfDecimalPlaces);
           int newr=(int)(r*amountOfDecimalPlaces);
           lowestXvalue=newh-newr;
           highestXvalue=newh+newr;
           int PossibleXvalue=lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
    
           return  PossibleXvalue/amountOfDecimalPlaces;
      }
       else
        lowestXvalue=(int)(h-r);
        highestXvalue=(int)(h+r);   // --> Possible error here
       return lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);    
    }
 
    public double nextRainDrop_y()
    {
        int lowestXvalue;
        int highestXvalue;
        if(k != (int)k)
        {
           double amountOfDecimalPlaces=Math.pow(10,String.valueOf(k).split("\\.")[1].length());
           int newh=(int)(k*amountOfDecimalPlaces);
           int newr=(int)(r*amountOfDecimalPlaces);
           lowestXvalue=newh-newr;
           highestXvalue=newh+newr;
           int PossibleXvalue=lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
    
           return  PossibleXvalue/amountOfDecimalPlaces;
       }
       else
        lowestXvalue=(int)(k-r);
        highestXvalue=(int)(k+r); // --> Possible error here, too
       return lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
    
    }
 
    public boolean insideCircle(double x,double y){
        if((x-h)*(x-h)+(y-k)*(y-k)<=r*r)
        return true;
        return false;
    }
}
Please run my code and figure out where the error. I don't understand what I'm doing wrong.
 
Last edited by a moderator:
Physics news on Phys.org
  • #2
Indigo_Blue said:

Homework Statement


There is a square and a circle is inscribed inside. Simulate an experiment where raindrops drop on this surface. Some raindrops can drop in or on the border of the circle. Some can drop outside the circle. The area of the square divided by the area of the circle gives you pi. If we manipulate this equation using the amount of times a raindrop drops into or outside the circle, we can approximate pi. The calculated value of pi is supposed to become more accurate as we run the simulation more. However, I am always getting these values:
4.695652173913044
4.333333333333333
4.321198252548367
4.378718056137411
4.337363058811759
The number does not seem to get closer to pi even if I increase the amount of times the loop iterates. I cannot find the error that would make this number off from pi.

Homework Equations


(x – h)^2 + (y – k)^2 = r^2 is the equation of a circle.

The Attempt at a Solution


There are two classes in my code.
Mentor note: I added code tags to make your code more readable.
Main class
Java:
public class Main {

    public static void main(String[] args) {
       MonteCarlo circle=new MonteCarlo(5,3,2);
  
       int cirCount=0; int sqrCount=0; double area=(Math.pow(2*circle.r,2));
       for(int x=0;x<100;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
           cirCount++;
           else
           sqrCount++;
      
       }
        System.out.println((cirCount*(area))/(sqrCount*circle.r*circle.r));
        cirCount=0; sqrCount=0;
        for(int x=0;x<1000;x++)
        {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
           cirCount++;
           else
           sqrCount++;
      
       }
        System.out.println(cirCount*(area)/(sqrCount*(circle.r*circle.r)));
        cirCount=0; sqrCount=0;
        for(int x=0;x<10000;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
              cirCount++;
           else
              sqrCount++;      
       }
       System.out.println(cirCount*(area)/(sqrCount*circle.r*circle.r));
       cirCount=0; sqrCount=0;
       for(int x=0;x<100000;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
              cirCount++;
           else
              sqrCount++;      
       }
       System.out.println(cirCount*(area)/(sqrCount*circle.r*circle.r));
       cirCount=0; sqrCount=0;
       for(int x=0;x<1000000;x++)
       {
           if(circle.insideCircle(circle.nextRainDrop_x(),circle.nextRainDrop_y())==true)
              cirCount++;
           else
              sqrCount++;      
       }
       System.out.println((cirCount*(area))/(sqrCount*circle.r*circle.r));   
    }
}

MonteCarlo class
import java.util.*;
public class MonteCarlo{
 
    public double h;
    public double k;
    public double r;
    private Random rndm= new Random();
 
    public  MonteCarlo(double x,double y, double z)
    {
        h=x; k=y; r=z;
    }
 
    public double nextRainDrop_x()
    {
        int lowestXvalue;
        int highestXvalue;
        if(h != (int)h){
           double amountOfDecimalPlaces=Math.pow(10,String.valueOf(h).split("\\.")[1].length());
           int newh=(int)(h*amountOfDecimalPlaces);
           int newr=(int)(r*amountOfDecimalPlaces);
           lowestXvalue=newh-newr;
           highestXvalue=newh+newr;
           int PossibleXvalue=lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
   
           return  PossibleXvalue/amountOfDecimalPlaces;
      }
       else
        lowestXvalue=(int)(h-r);
        highestXvalue=(int)(h+r);   // --> Possible error here
       return lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);   
    }
 
    public double nextRainDrop_y()
    {
        int lowestXvalue;
        int highestXvalue;
        if(k != (int)k)
        {
           double amountOfDecimalPlaces=Math.pow(10,String.valueOf(k).split("\\.")[1].length());
           int newh=(int)(k*amountOfDecimalPlaces);
           int newr=(int)(r*amountOfDecimalPlaces);
           lowestXvalue=newh-newr;
           highestXvalue=newh+newr;
           int PossibleXvalue=lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
   
           return  PossibleXvalue/amountOfDecimalPlaces;
       }
       else
        lowestXvalue=(int)(k-r);
        highestXvalue=(int)(k+r); // --> Possible error here, too
       return lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
   
    }
 
    public boolean insideCircle(double x,double y){
        if((x-h)*(x-h)+(y-k)*(y-k)<=r*r)
        return true;
        return false;
    }
}
Please run my code and figure out where the error. I don't understand what I'm doing wrong.
I spotted two rookie mistakes in your code; possibly there are others I didn't catch. I've marked them with comments like this: // --> Possible error here
The errors are in nextRaindrop_x() and nextRaindrop_y(). Here's from the first of these functions.
Java:
       else
        lowestXvalue=(int)(h-r);
        highestXvalue=(int)(h+r);   // --> Possible error here
       return lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
Judging from how you wrote this, I believe you think that the three lines following else will execute of the condition in the if part is false. That is not true. Only the first line under else is the else clause. The 2nd and 3rd lines execute always, regardless of whether the if condition is true or false.
To correct the problem, rewrite it like this:
Java:
       else {
          lowestXvalue=(int)(h-r);
          highestXvalue=(int)(h+r);   
       }
       return lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);

Also, your insideCircle() function is confusing, but doesn't cause an error.
To make it clearer to the reader, it should be written like this:
Java:
    public boolean insideCircle(double x,double y){
        if((x-h)*(x-h)+(y-k)*(y-k)<=r*r)
            return true;
        return false;
    }
or this:
Java:
    public boolean insideCircle(double x,double y){
        if((x-h)*(x-h)+(y-k)*(y-k)<=r*r)
        {
            return true;
        }
        return false;
    }
 
  • #3
I added the curly braces here, but it didn't made a difference.I'm still not close to the approximated pi value of 3.14159
" else{
lowestXvalue=(int)(k-r);
highestXvalue=(int)(k+r);
return lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);} "

I'm still getting outputs like 4.888888888888889,4.4033613445378155,4.417508417508418,4.3137613534803485,4.325874737214579 and I think it could be because some numbers are losing precision when multiplied/divided since they are not casted as doubles.

These are the directions if you are wondering what the point of the experiment is.
Project... Monte Carlo Technique
Imagine a giant square painted outdoors, on the ground, with a painted circle inscribed in it.
Next, image that it’s raining and that we have the ability to monitor every raindrop that hits
inside the square. Some of those raindrops will also fall inside the circle, and a few will fall in
the corners and be inside the square, but not inside the circle. Keep a tally of the raindrops that
hit inside the square (sqrCount) and those that also hit inside the circle (cirCount).
The ratio of these two counts should equal the ratio of the areas as follows: (Understanding
this statement is essential. It is the very premise of this problem.)
sqrCount / cirCount = (Area of square) / (Area of circle)
sqrCount / cirCount = side^2 / (π * r^2)
Solving for π from this equation we get
π = cirCount * (side^2) / (sqrCount * r^2)

So why did we solve for π? We already know that it’s ≅ 3.14159. We simply want to illustrate
that by a simulation (raindrop positions) we can solve for various things, in this case something
we already know. The fact that we already know π just makes it that much easier to check our
answer and verify the technique.

We are going to build a class called
MonteCarlo in which the constructor will
establish the size and position of our square
and circle. Public state variables inside this
class will be h, k, and r. These are enough to
specify the position and size of our circle and
square as shown in the figure to the right.

Fig. 29-1

The requirements of your MonteCarlo class are:
1. The constructor should receive h, k, and r as described above and use them to set the
instance fields (state variables).
2. State variables h, k, and r are public doubles. Create a private instance field as an object
of the Random class. Call it rndm.
3. The nextRainDrop_x( ) method should return a double that corresponds to a random
raindrop’s x position. The range of x values should be confined to the square shown
above. No parameters are passed to this method.
4. The nextRainDrop_y( ) method should return a double that corresponds to a random
raindrop’s y position. The range of y values should be confined to the square shown
above. No parameters are passed to this method.
5. The method insideCircle(double x, double y ) returns a boolean. A true is returned if the
parameters x and y that are passed are either inside or on the circle.
In writing this method, you must remember that the equation of a circle is
(x – h)^2 + (y – k)^2= r^2
...where (h,k) is the center and r is the radius.

Also, the test for a point (x, y) being either inside or on a circle is
(x – h)^2 + (y – k) ^2 <= r^2

You will need to build a Tester class with the following features:
1. Class name, Tester
2. There is only one method, the main( ) method.
3. Create a MonteCarlo object called mcObj in which the center of the circle is at (5, 3)
and the radius is 2.
4. Set up a for-loop for 100 iterations:
5. Inside the loop obtain the random coordinates of a rain drop using the
nextRainDrop_x( ) and nextRainDrop_y( ) methods.
6. Using the x and y just obtained, pass them as arguments to the insideCircle( ) method
to decide if our “raindrop” is inside the circle. If insideCircle( ) returns a true then
increment cirCount.
7. Increment sqrCount on each pass through the loop.
8. After the loop, calculate and print your estimate for π according to the solution for π
on the previous page.
9. Change the number of iterations of the loop to 1000 and run the program again.
Repeat for 10,000, 100,000, and 1,000,000 iterations. The estimate for π should
improve as the number of iterations increases.
 
Last edited:
  • #4
I'm not understanding your code. For each iteration, you need to generate a random x value such that 3.0 <= x <= 7.0, and a random y value such that 1.0 <= y <= 5.0.
Your randomRaindrop functions have this or similar code in them:
Java:
int PossibleXvalue=lowestXvalue+rndm.nextInt(highestXvalue+1-lowestXvalue);
You do NOT want an int value for either the x or y value, so you need to come up with a way to generate floating point values, not ints, for the two coordinates. This is all or most of the problem with the bad results you're getting.

Instead of using the nextInt() method on the Random class, use nextDouble(). This returns a double in the range of 0.0 to 1.0. For the x value of your raindrop, multiply by 2.0, and then add 5.0, in that order. This will give you a number between 5.0 and 7.0. For the y value, also multiply by 2.0, but add 3.0. This will give you a y value between between 3.0 and 5.0.

When you have a pair of numbers for the raindrop location, determine whether it is in the upper right quadrant of the circle. The area of 1/4 of the circle is exactly ##\pi##. The area of the quarter square whose lower left corner is (5.0, 3.0) and whose upper right corner is (7.0, 5.0) is exactly 4. Compare the number of raindrops in the upper right quadrant of the circle to the number that fall in the upper right square. The ratio should be close to ##\frac \pi 4##, so multiply this ratio by 4 to get your approximation to ##\pi##.
 
Last edited:
  • #5
I figured out what I was doing wrong. I did not need an "else" statement in my for loops and I was supposed to used nextDouble() to generate the numbers. I knew I was supposed to used nextDouble() but I could not figure out how to make it print the highest value in a given range since it always excludes it so I tried using nextInt() to avoid that. I knew that a generated number from nextDouble() would be infinitesimally close to the highest number but I wanted to make my output accurate to 20 decimal places. For simplicity, all I needed in my my method was "return (h-r)+rndm.nextDouble()*2*r;" only if I expected the parameters to be integers, but I thought if there were floating point numbers,then it would be less accurate using nextDouble().
 

FAQ: Why Is My Java Monte Carlo Simulation Not Approximating Pi Accurately?

1. What is a Monte Carlo experiment in Java?

A Monte Carlo experiment in Java is a computational technique that uses random sampling to simulate a complex system or process. It is commonly used in scientific research and engineering to estimate the behavior of a system or to solve problems that are too difficult to solve analytically.

2. How does a Monte Carlo experiment work in Java?

A Monte Carlo experiment in Java works by generating a large number of random samples and using them to approximate the behavior of a system. These samples are then analyzed and used to make predictions or solve problems. The more samples that are generated, the more accurate the results will be.

3. What are the advantages of using Java for a Monte Carlo experiment?

Java is a high-level, object-oriented programming language that is well-suited for complex simulations and calculations. It offers a wide range of libraries and tools that make it easy to implement a Monte Carlo experiment, and its platform independence allows for easy distribution and use on different operating systems.

4. What are the limitations of a Monte Carlo experiment in Java?

One limitation of a Monte Carlo experiment in Java is that it can be computationally intensive, especially when generating a large number of samples. This can lead to longer processing times and may require a powerful computer to run efficiently. Additionally, the accuracy of the results depends on the quality and quantity of the random samples generated.

5. What are some real-world applications of a Monte Carlo experiment in Java?

A Monte Carlo experiment in Java has numerous real-world applications, including in finance, physics, engineering, and computer science. It can be used to simulate stock market behavior, analyze the performance of a new product design, or optimize the routing of a transportation network. It is also commonly used in machine learning and data analysis to generate training data and test algorithms.

Similar threads

Replies
7
Views
2K
Replies
1
Views
1K
Replies
2
Views
1K
Replies
5
Views
2K
Replies
1
Views
2K
Replies
2
Views
2K
Replies
4
Views
2K
Replies
12
Views
3K
Back
Top