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

AI Thread Summary
The Java Monte Carlo simulation aims to approximate pi by calculating the ratio of the area of a circle inscribed in a square based on random "raindrop" placements. Users report consistently high output values for pi, such as 4.695 and 4.333, indicating inaccuracies despite increasing iterations. Potential errors are identified in the `nextRainDrop_x()` and `nextRainDrop_y()` methods, particularly in how the `highestXvalue` and `lowestXvalue` are calculated, which may not correctly reflect the intended range. Additionally, precision issues may arise from using integers instead of doubles during calculations. Adjustments to the code's structure and data types are recommended to improve accuracy.
Indigo_Blue
Messages
5
Reaction score
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:
Java:
<Your java 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
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;
    }
 
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:
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:
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().
 
Thread 'Have I solved this structural engineering equation correctly?'
Hi all, I have a structural engineering book from 1979. I am trying to follow it as best as I can. I have come to a formula that calculates the rotations in radians at the rigid joint that requires an iterative procedure. This equation comes in the form of: $$ x_i = \frac {Q_ih_i + Q_{i+1}h_{i+1}}{4K} + \frac {C}{K}x_{i-1} + \frac {C}{K}x_{i+1} $$ Where: ## Q ## is the horizontal storey shear ## h ## is the storey height ## K = (6G_i + C_i + C_{i+1}) ## ## G = \frac {I_g}{h} ## ## C...

Similar threads

Replies
5
Views
3K
Replies
1
Views
2K
Replies
12
Views
4K
Replies
6
Views
2K
Replies
1
Views
3K
Replies
5
Views
3K
Replies
2
Views
3K
Replies
5
Views
9K
Back
Top