I'm trying to write a code that approximates the value of PI. What I'm doing is:
drawing a circle inside a rectangle
drawing random points inside the rectangle and circle
calculating the ratio between rect/cicle
calculating 4/ratio
that should be PI
This my code:
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Random;
public class Main extends Frame {
int width = 800;
ArrayList<Point> list = new ArrayList<Point>();
public void points(Graphics g) {
int numPoint = 10000000;
for (int i = 0; i < numPoint; i++) {
int min = 23;
int max = 23 + width;
Random rand = new Random();
int x = rand.nextInt(width);
int y = (int) (Math.random() * (max - min + 1) + min);
Point temp = new Point(x, y);
list.add(temp);
if (inCircle(temp)) {
g.setColor(Color.green);
} else {
g.setColor(Color.blue);
}
g.drawLine(x, y, x, y);
}
}
public void paint(Graphics g) {
g.fillRect(0, 0, 1000, 1000);
int x = width / 2;
int y = width / 2 + 23;
int radius = width / 2;
g.setColor(Color.WHITE);
g.drawOval(x - radius, y - radius, radius * 2, radius * 2);
g.drawRect(0, 23, width, width);
points(g);
calculatingPI();
}
public void calculatingPI() {
double inCircle = 0;
double inRect = list.size();
for (Point p : list) {
if (inCircle(p)) {
inCircle++;
}
}
double ratio = inRect / inCircle;
System.out.print("PI is approximated to: " + 4 / ratio + " ");
}
public boolean inCircle(Point p) {
Point center = new Point(width / 2, width / 2 + 23);
return center.distance(p) <= width / 2;
}
public static void main(String[] args) {
Frame frame = new Main();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
// circle coordinates.
frame.setSize(800, 1000);
frame.setVisible(true);
}
}
It works quite fine, even if most of the time the number is around 1,13 which is not a great approx.
The question is: The more I decrease the size of the rectangle and circle, (without changing the number of points), the less PI becomes accurate. I don't understand, why is that? Is there a problem in my code?
Shouldn't it be the opposite? The smallest the area, the more points are accurate, the more PI is accurate. Why is isn't it the case?
You are using integer pixels. This means the smaller you make your "circle", the worse it approximates a true circle. For example here's the circle within a 3x3 pixel square: it does not look circular at all.
█
███
█
To get a better approximation, use double
floating point numbers instead of integers. Use Point2D.Double
instead of the Point
class:
ArrayList<Point2D.Double> list = new ArrayList<>();
To generate the random points:
double x = Math.random() * width;
double y = Math.random() * (max - min) + min;
Point2D.Double temp = new Point2D.Double(x, y);
Note that where you had max-min+1
, the +1 has to be removed.
To test if the point is within the circle:
public boolean inCircle(Point2D.Double p) {
Point2D.Double center = new Point2D.Double(width / 2d, width / 2d + 23);
return center.distance(p) <= width / 2d;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.