简体   繁体   中英

Calculating PI approximation with Java

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM