Skip to content

Commit 657bd0f

Browse files
Adding PiApproximation algo
1 parent f9a9ccb commit 657bd0f

File tree

2 files changed

+245
-0
lines changed

2 files changed

+245
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.thealgorithms.maths;
2+
import java.util.ArrayList;
3+
import java.util.List;
4+
import java.util.Random;
5+
6+
/**
7+
* Implementation to calculate an estimate of the number π (Pi).
8+
*
9+
* We take a random point P with coordinates (x, y) such that 0 ≤ x ≤ 1 and 0 ≤ y ≤ 1.
10+
* If x² + y² ≤ 1, then the point is inside the quarter disk of radius 1,
11+
* else the point is outside. We know that the probability of the point being
12+
* inside the quarter disk is equal to π/4.
13+
*
14+
*
15+
* @author [Yash Rajput](https://github.com/the-yash-rajput)
16+
*/
17+
public class PiApproximation {
18+
19+
/**
20+
* Structure representing a point with coordinates (x, y)
21+
* where 0 ≤ x ≤ 1 and 0 ≤ y ≤ 1.
22+
*/
23+
static class Point {
24+
double x;
25+
double y;
26+
27+
public Point(double x, double y) {
28+
this.x = x;
29+
this.y = y;
30+
}
31+
}
32+
33+
/**
34+
* This function uses the points in a given list (drawn at random)
35+
* to return an approximation of the number π.
36+
*
37+
* @param pts List of points where each point contains x and y coordinates
38+
* @return An estimate of the number π
39+
*/
40+
public static double approximatePi(List<Point> pts) {
41+
double count = 0; // Points in circle
42+
43+
for (Point p : pts) {
44+
if ((p.x * p.x) + (p.y * p.y) <= 1) {
45+
count++;
46+
}
47+
}
48+
49+
return 4.0 * count / pts.size();
50+
}
51+
52+
/**
53+
* Generates random points for testing the Pi approximation.
54+
*
55+
* @param numPoints Number of random points to generate
56+
* @return List of random points
57+
*/
58+
public static List<Point> generateRandomPoints(int numPoints) {
59+
List<Point> points = new ArrayList<>();
60+
Random rand = new Random();
61+
62+
for (int i = 0; i < numPoints; i++) {
63+
double x = rand.nextDouble(); // Random value between 0 and 1
64+
double y = rand.nextDouble(); // Random value between 0 and 1
65+
points.add(new Point(x, y));
66+
}
67+
68+
return points;
69+
}
70+
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package com.thealgorithms.maths;
2+
3+
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
import static org.junit.jupiter.api.Assertions.assertTrue;
11+
12+
class PiApproximationTest {
13+
14+
private static final double DELTA = 0.5; // Tolerance for Pi approximation
15+
private static final double TIGHT_DELTA = 0.1; // Tighter tolerance for large samples
16+
17+
/**
18+
* Test with known points that are all inside the quarter circle.
19+
*/
20+
@Test
21+
public void testAllPointsInside() {
22+
List<PiApproximation.Point> points = new ArrayList<>();
23+
points.add(new PiApproximation.Point(0.0, 0.0)); // Origin
24+
points.add(new PiApproximation.Point(0.5, 0.5)); // Inside
25+
points.add(new PiApproximation.Point(0.3, 0.3)); // Inside
26+
27+
double result = PiApproximation.approximatePi(points);
28+
// All points inside, so result should be 4.0
29+
assertEquals(4.0, result, 0.001);
30+
}
31+
32+
/**
33+
* Test with known points that are all outside the quarter circle.
34+
*/
35+
@Test
36+
public void testAllPointsOutside() {
37+
List<PiApproximation.Point> points = new ArrayList<>();
38+
points.add(new PiApproximation.Point(1.0, 1.0)); // Corner - outside
39+
points.add(new PiApproximation.Point(0.9, 0.9)); // Outside
40+
41+
double result = PiApproximation.approximatePi(points);
42+
// No points inside, so result should be 0.0
43+
assertEquals(0.0, result, 0.001);
44+
}
45+
46+
/**
47+
* Test with mixed points (some inside, some outside).
48+
*/
49+
@Test
50+
public void testMixedPoints() {
51+
List<PiApproximation.Point> points = new ArrayList<>();
52+
// Inside points
53+
points.add(new PiApproximation.Point(0.0, 0.0));
54+
points.add(new PiApproximation.Point(0.5, 0.5));
55+
// Outside points
56+
points.add(new PiApproximation.Point(1.0, 1.0));
57+
points.add(new PiApproximation.Point(0.9, 0.9));
58+
59+
double result = PiApproximation.approximatePi(points);
60+
// 2 out of 4 points inside: 4 * 2/4 = 2.0
61+
assertEquals(2.0, result, 0.001);
62+
}
63+
64+
/**
65+
* Test with boundary point (on the circle).
66+
*/
67+
@Test
68+
public void testBoundaryPoint() {
69+
List<PiApproximation.Point> points = new ArrayList<>();
70+
points.add(new PiApproximation.Point(1.0, 0.0)); // On circle: x² + y² = 1
71+
points.add(new PiApproximation.Point(0.0, 1.0)); // On circle
72+
73+
double result = PiApproximation.approximatePi(points);
74+
// Boundary points should be counted as inside (≤ 1)
75+
assertEquals(4.0, result, 0.001);
76+
}
77+
78+
/**
79+
* Test with small random sample (moderate accuracy expected).
80+
*/
81+
@Test
82+
public void testSmallRandomSample() {
83+
List<PiApproximation.Point> points = PiApproximation.generateRandomPoints(1000);
84+
double result = PiApproximation.approximatePi(points);
85+
86+
// With 1000 points, result should be reasonably close to π
87+
assertEquals(Math.PI, result, DELTA);
88+
}
89+
90+
/**
91+
* Test with large random sample (better accuracy expected).
92+
*/
93+
@Test
94+
public void testLargeRandomSample() {
95+
List<PiApproximation.Point> points = PiApproximation.generateRandomPoints(100000);
96+
double result = PiApproximation.approximatePi(points);
97+
98+
// With 100000 points, result should be very close to π
99+
assertEquals(Math.PI, result, TIGHT_DELTA);
100+
}
101+
102+
/**
103+
* Test that result is always positive.
104+
*/
105+
@Test
106+
public void testResultIsPositive() {
107+
List<PiApproximation.Point> points = PiApproximation.generateRandomPoints(1000);
108+
double result = PiApproximation.approximatePi(points);
109+
110+
assertTrue(result >= 0, "Pi approximation should be positive");
111+
}
112+
113+
/**
114+
* Test that result is bounded (0 ≤ result ≤ 4).
115+
*/
116+
@Test
117+
public void testResultIsBounded() {
118+
List<PiApproximation.Point> points = PiApproximation.generateRandomPoints(1000);
119+
double result = PiApproximation.approximatePi(points);
120+
121+
assertTrue(result >= 0 && result <= 4,
122+
"Pi approximation should be between 0 and 4");
123+
}
124+
125+
/**
126+
* Test with single point inside.
127+
*/
128+
@Test
129+
public void testSinglePointInside() {
130+
List<PiApproximation.Point> points = new ArrayList<>();
131+
points.add(new PiApproximation.Point(0.0, 0.0));
132+
133+
double result = PiApproximation.approximatePi(points);
134+
assertEquals(4.0, result, 0.001);
135+
}
136+
137+
/**
138+
* Test with single point outside.
139+
*/
140+
@Test
141+
public void testSinglePointOutside() {
142+
List<PiApproximation.Point> points = new ArrayList<>();
143+
points.add(new PiApproximation.Point(1.0, 1.0));
144+
145+
double result = PiApproximation.approximatePi(points);
146+
assertEquals(0.0, result, 0.001);
147+
}
148+
149+
/**
150+
* Test that generated points are within valid range [0, 1].
151+
*/
152+
@Test
153+
public void testGeneratedPointsInRange() {
154+
List<PiApproximation.Point> points = PiApproximation.generateRandomPoints(100);
155+
156+
for (PiApproximation.Point p : points) {
157+
assertTrue(p.x >= 0 && p.x <= 1,
158+
"X coordinate should be between 0 and 1");
159+
assertTrue(p.y >= 0 && p.y <= 1,
160+
"Y coordinate should be between 0 and 1");
161+
}
162+
}
163+
164+
/**
165+
* Test that the correct number of points are generated.
166+
*/
167+
@Test
168+
public void testCorrectNumberOfPointsGenerated() {
169+
int expectedSize = 500;
170+
List<PiApproximation.Point> points =
171+
PiApproximation.generateRandomPoints(expectedSize);
172+
173+
assertEquals(expectedSize, points.size());
174+
}
175+
}

0 commit comments

Comments
 (0)