Skip to content

Commit e21aee8

Browse files
Priyanshu1303dPriyanshu1303d
andauthored
[FEAT] Add Newton's Law of Gravitation algorithm (#6855)
Co-authored-by: Priyanshu1303d <[email protected]>
1 parent ab65ac6 commit e21aee8

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.thealgorithms.physics;
2+
3+
/**
4+
* Implements Newton's Law of Universal Gravitation.
5+
* Provides simple static methods to calculate gravitational force and circular orbit velocity.
6+
*
7+
* @author [Priyanshu Kumar Singh](https://github.com/Priyanshu1303d)
8+
* @see <a href="https://en.wikipedia.org/wiki/Newton%27s_law_of_universal_gravitation">Wikipedia</a>
9+
*/
10+
public final class Gravitation {
11+
12+
/** Gravitational constant in m^3 kg^-1 s^-2 */
13+
public static final double GRAVITATIONAL_CONSTANT = 6.67430e-11;
14+
15+
/**
16+
* Private constructor to prevent instantiation of this utility class.
17+
*/
18+
private Gravitation() {
19+
}
20+
21+
/**
22+
* Calculates the gravitational force vector exerted by one body on another.
23+
*
24+
* @param m1 Mass of the first body (kg).
25+
* @param x1 X-position of the first body (m).
26+
* @param y1 Y-position of the first body (m).
27+
* @param m2 Mass of the second body (kg).
28+
* @param x2 X-position of the second body (m).
29+
* @param y2 Y-position of the second body (m).
30+
* @return A double array `[fx, fy]` representing the force vector on the second body.
31+
*/
32+
public static double[] calculateGravitationalForce(double m1, double x1, double y1, double m2, double x2, double y2) {
33+
double dx = x1 - x2;
34+
double dy = y1 - y2;
35+
double distanceSq = dx * dx + dy * dy;
36+
37+
// If bodies are at the same position, force is zero to avoid division by zero.
38+
if (distanceSq == 0) {
39+
return new double[] {0, 0};
40+
}
41+
42+
double distance = Math.sqrt(distanceSq);
43+
double forceMagnitude = GRAVITATIONAL_CONSTANT * m1 * m2 / distanceSq;
44+
45+
// Calculate the components of the force vector
46+
double fx = forceMagnitude * (dx / distance);
47+
double fy = forceMagnitude * (dy / distance);
48+
49+
return new double[] {fx, fy};
50+
}
51+
52+
/**
53+
* Calculates the speed required for a stable circular orbit.
54+
*
55+
* @param centralMass The mass of the central body (kg).
56+
* @param radius The radius of the orbit (m).
57+
* @return The orbital speed (m/s).
58+
* @throws IllegalArgumentException if mass or radius are not positive.
59+
*/
60+
public static double calculateCircularOrbitVelocity(double centralMass, double radius) {
61+
if (centralMass <= 0 || radius <= 0) {
62+
throw new IllegalArgumentException("Mass and radius must be positive.");
63+
}
64+
return Math.sqrt(GRAVITATIONAL_CONSTANT * centralMass / radius);
65+
}
66+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.thealgorithms.physics;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
7+
import org.junit.jupiter.api.DisplayName;
8+
import org.junit.jupiter.api.Test;
9+
10+
/**
11+
* Unit tests for the Gravitation utility class.
12+
*/
13+
final class GravitationTest {
14+
15+
// A small tolerance (delta) for comparing floating-point numbers
16+
private static final double DELTA = 1e-9;
17+
private static final double G = Gravitation.GRAVITATIONAL_CONSTANT;
18+
19+
@Test
20+
@DisplayName("Test gravitational force between two bodies on the x-axis")
21+
void testSimpleForceCalculation() {
22+
// Force on body 2 should be F = G*1*1 / 1^2 = G, directed towards body 1 (negative x)
23+
double[] forceOnB = Gravitation.calculateGravitationalForce(1.0, 0, 0, 1.0, 1, 0);
24+
assertArrayEquals(new double[] {-G, 0.0}, forceOnB, DELTA);
25+
26+
// Force on body 1 should be equal and opposite (positive x)
27+
double[] forceOnA = Gravitation.calculateGravitationalForce(1.0, 1, 0, 1.0, 0, 0);
28+
assertArrayEquals(new double[] {G, 0.0}, forceOnA, DELTA);
29+
}
30+
31+
@Test
32+
@DisplayName("Test gravitational force in a 2D plane")
33+
void test2DForceCalculation() {
34+
// Body 1 at (0,0) with mass 2kg
35+
// Body 2 at (3,4) with mass 1kg
36+
// Distance is sqrt(3^2 + 4^2) = 5 meters
37+
double magnitude = 2.0 * G / 25.0; // G * 2 * 1 / 5^2
38+
// Unit vector from 2 to 1 is (-3/5, -4/5)
39+
double expectedFx = magnitude * -3.0 / 5.0; // -6G / 125
40+
double expectedFy = magnitude * -4.0 / 5.0; // -8G / 125
41+
42+
double[] forceOnB = Gravitation.calculateGravitationalForce(2.0, 0, 0, 1.0, 3, 4);
43+
assertArrayEquals(new double[] {expectedFx, expectedFy}, forceOnB, DELTA);
44+
}
45+
46+
@Test
47+
@DisplayName("Test overlapping bodies should result in zero force")
48+
void testOverlappingBodies() {
49+
double[] force = Gravitation.calculateGravitationalForce(1000.0, 1.5, -2.5, 500.0, 1.5, -2.5);
50+
assertArrayEquals(new double[] {0.0, 0.0}, force, DELTA);
51+
}
52+
53+
@Test
54+
@DisplayName("Test circular orbit velocity with simple values")
55+
void testCircularOrbitVelocity() {
56+
// v = sqrt(G*1/1) = sqrt(G)
57+
double velocity = Gravitation.calculateCircularOrbitVelocity(1.0, 1.0);
58+
assertEquals(Math.sqrt(G), velocity, DELTA);
59+
}
60+
61+
@Test
62+
@DisplayName("Test orbital velocity with real-world-ish values (LEO)")
63+
void testEarthOrbitVelocity() {
64+
// Mass of Earth ~5.972e24 kg
65+
// Radius of LEO ~6,771,000 m (Earth radius + 400km)
66+
double earthMass = 5.972e24;
67+
double leoRadius = 6.771e6;
68+
// FIX: Updated expected value to match the high-precision calculation
69+
double expectedVelocity = 7672.4904;
70+
71+
double velocity = Gravitation.calculateCircularOrbitVelocity(earthMass, leoRadius);
72+
assertEquals(expectedVelocity, velocity, 0.0001); // Use a larger delta for big numbers
73+
}
74+
75+
@Test
76+
@DisplayName("Test invalid inputs for orbital velocity throw exception")
77+
void testInvalidOrbitalVelocityInputs() {
78+
assertThrows(IllegalArgumentException.class, () -> Gravitation.calculateCircularOrbitVelocity(0, 100));
79+
assertThrows(IllegalArgumentException.class, () -> Gravitation.calculateCircularOrbitVelocity(-1000, 100));
80+
assertThrows(IllegalArgumentException.class, () -> Gravitation.calculateCircularOrbitVelocity(1000, 0));
81+
assertThrows(IllegalArgumentException.class, () -> Gravitation.calculateCircularOrbitVelocity(1000, -100));
82+
}
83+
}

0 commit comments

Comments
 (0)