From 40e52c19608f838469ffa7bd0cc3bef28996c2ea Mon Sep 17 00:00:00 2001 From: Priyanshu1303d Date: Fri, 31 Oct 2025 23:36:13 +0530 Subject: [PATCH] [FEAT] Add Coulomb's Law for electrostatics --- .../thealgorithms/maths/JugglerSequence.java | 2 +- .../thealgorithms/physics/CoulombsLaw.java | 80 ++++++++++++++ .../physics/CoulombsLawTest.java | 100 ++++++++++++++++++ 3 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/thealgorithms/physics/CoulombsLaw.java create mode 100644 src/test/java/com/thealgorithms/physics/CoulombsLawTest.java diff --git a/src/main/java/com/thealgorithms/maths/JugglerSequence.java b/src/main/java/com/thealgorithms/maths/JugglerSequence.java index 702310a1f295..a459b4b6d4bb 100644 --- a/src/main/java/com/thealgorithms/maths/JugglerSequence.java +++ b/src/main/java/com/thealgorithms/maths/JugglerSequence.java @@ -43,7 +43,7 @@ public static void jugglerSequence(int inputNumber) { seq.add(n + ""); } String res = String.join(",", seq); - System.out.println(res); + System.out.print(res + "\n"); } // Driver code diff --git a/src/main/java/com/thealgorithms/physics/CoulombsLaw.java b/src/main/java/com/thealgorithms/physics/CoulombsLaw.java new file mode 100644 index 000000000000..3a3ad3e0d223 --- /dev/null +++ b/src/main/java/com/thealgorithms/physics/CoulombsLaw.java @@ -0,0 +1,80 @@ +package com.thealgorithms.physics; + +/** + * Implements Coulomb's Law for electrostatics. + * Provides simple static methods to calculate electrostatic force and circular orbit velocity. + * + * @author [Priyanshu Singh](https://github.com/Priyanshu1303d) + * @see Wikipedia + */ +public final class CoulombsLaw { + + /** Coulomb's constant in N·m²/C² */ + public static final double COULOMBS_CONSTANT = 8.9875517923e9; + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private CoulombsLaw() { + } + + /** + * Calculates the electrostatic force vector exerted by one charge on another. + * The returned vector is the force *on* the second charge (q2). + * + * @param q1 Charge of the first particle (in Coulombs). + * @param x1 X-position of the first particle (m). + * @param y1 Y-position of the first particle (m). + * @param q2 Charge of the second particle (in Coulombs). + * @param x2 X-position of the second particle (m). + * @param y2 Y-position of the second particle (m). + * @return A double array `[fx, fy]` representing the force vector on the second charge. + */ + public static double[] calculateForceVector(double q1, double x1, double y1, double q2, double x2, double y2) { + // Vector from 1 to 2 + double dx = x2 - x1; + double dy = y2 - y1; + double distanceSq = dx * dx + dy * dy; + + // If particles are at the same position, force is zero to avoid division by zero. + if (distanceSq == 0) { + return new double[] {0, 0}; + } + + double distance = Math.sqrt(distanceSq); + // Force magnitude: k * (q1 * q2) / r^2 + // A positive result is repulsive (pushes q2 away from q1). + // A negative result is attractive (pulls q2 toward q1). + double forceMagnitude = COULOMBS_CONSTANT * q1 * q2 / distanceSq; + + // Calculate the components of the force vector + // (dx / distance) is the unit vector pointing from 1 to 2. + double fx = forceMagnitude * (dx / distance); + double fy = forceMagnitude * (dy / distance); + + return new double[] {fx, fy}; + } + + /** + * Calculates the speed required for a stable circular orbit of a charged particle + * around a central charge (e.g., an electron orbiting a nucleus). + * + * @param centralCharge The charge of the central body (in Coulombs). + * @param orbitingCharge The charge of the orbiting body (in Coulombs). + * @param orbitingMass The mass of the orbiting body (in kg). + * @param radius The radius of the orbit (in m). + * @return The orbital speed (in m/s). + * @throws IllegalArgumentException if mass or radius are not positive. + */ + public static double calculateCircularOrbitVelocity(double centralCharge, double orbitingCharge, double orbitingMass, double radius) { + if (orbitingMass <= 0 || radius <= 0) { + throw new IllegalArgumentException("Orbiting mass and radius must be positive."); + } + + // We only need the magnitude of the force, which is always positive. + double forceMagnitude = Math.abs(COULOMBS_CONSTANT * centralCharge * orbitingCharge) / (radius * radius); + + // F_c = m * v^2 / r => v = sqrt(F_c * r / m) + return Math.sqrt(forceMagnitude * radius / orbitingMass); + } +} diff --git a/src/test/java/com/thealgorithms/physics/CoulombsLawTest.java b/src/test/java/com/thealgorithms/physics/CoulombsLawTest.java new file mode 100644 index 000000000000..9829e703bd10 --- /dev/null +++ b/src/test/java/com/thealgorithms/physics/CoulombsLawTest.java @@ -0,0 +1,100 @@ +package com.thealgorithms.physics; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the CoulombsLaw utility class. + */ +final class CoulombsLawTest { + + // A small tolerance (delta) for comparing floating-point numbers + private static final double DELTA = 1e-9; + private static final double K = CoulombsLaw.COULOMBS_CONSTANT; + + @Test + @DisplayName("Test repulsive force between two charges on the x-axis") + void testSimpleRepulsiveForce() { + // Two positive 1C charges, 1 meter apart. + // Force on q2 should be F = K*1*1 / 1^2 = K, directed away from q1 (positive x) + double[] forceOnB = CoulombsLaw.calculateForceVector(1.0, 0, 0, 1.0, 1, 0); + assertArrayEquals(new double[] {K, 0.0}, forceOnB, DELTA); + + // Force on q1 should be equal and opposite (negative x) + double[] forceOnA = CoulombsLaw.calculateForceVector(1.0, 1, 0, 1.0, 0, 0); + assertArrayEquals(new double[] {-K, 0.0}, forceOnA, DELTA); + } + + @Test + @DisplayName("Test attractive force between two charges on the x-axis") + void testSimpleAttractiveForce() { + // One positive 1C, one negative -1C, 1 meter apart. + // Force on q2 should be F = K*1*(-1) / 1^2 = -K, directed toward q1 (negative x) + double[] forceOnB = CoulombsLaw.calculateForceVector(1.0, 0, 0, -1.0, 1, 0); + assertArrayEquals(new double[] {-K, 0.0}, forceOnB, DELTA); + } + + @Test + @DisplayName("Test electrostatic force in a 2D plane (repulsive)") + void test2DRepulsiveForce() { + // q1 at (0,0) with charge +2C + // q2 at (3,4) with charge +1C + // Distance is 5 meters. + double magnitude = K * 2.0 * 1.0 / 25.0; // 2K/25 + // Unit vector from 1 to 2 is (3/5, 4/5) + double expectedFx = magnitude * (3.0 / 5.0); // 6K / 125 + double expectedFy = magnitude * (4.0 / 5.0); // 8K / 125 + + double[] forceOnB = CoulombsLaw.calculateForceVector(2.0, 0, 0, 1.0, 3, 4); + assertArrayEquals(new double[] {expectedFx, expectedFy}, forceOnB, DELTA); + } + + @Test + @DisplayName("Test overlapping charges should result in zero force") + void testOverlappingCharges() { + double[] force = CoulombsLaw.calculateForceVector(1.0, 1.5, -2.5, -1.0, 1.5, -2.5); + assertArrayEquals(new double[] {0.0, 0.0}, force, DELTA); + } + + @Test + @DisplayName("Test circular orbit velocity with simple values") + void testCircularOrbitVelocity() { + // v = sqrt( (K*1*1 / 1^2) * 1 / 1 ) = sqrt(K) + double velocity = CoulombsLaw.calculateCircularOrbitVelocity(1.0, 1.0, 1.0, 1.0); + assertEquals(Math.sqrt(K), velocity, DELTA); + } + + @Test + @DisplayName("Test orbital velocity for a Hydrogen atom (Bohr model)") + void testHydrogenAtomVelocity() { + // Charge of a proton + double protonCharge = 1.602176634e-19; + // Charge of an electron + double electronCharge = -1.602176634e-19; + // Mass of an electron + double electronMass = 9.1093837e-31; + // Bohr radius (avg distance) + double bohrRadius = 5.29177e-11; + + double expectedVelocity = 2.1876917e6; + + double velocity = CoulombsLaw.calculateCircularOrbitVelocity(protonCharge, electronCharge, electronMass, bohrRadius); + // Use a wider delta for this real-world calculation + assertEquals(expectedVelocity, velocity, 1.0); + } + + @Test + @DisplayName("Test invalid inputs for orbital velocity throw exception") + void testInvalidOrbitalVelocityInputs() { + // Non-positive mass + assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, 0, 100)); + assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, -1, 100)); + // Non-positive radius + assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, 1, 0)); + assertThrows(IllegalArgumentException.class, () -> CoulombsLaw.calculateCircularOrbitVelocity(1, 1, 1, -100)); + } +}