Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 54 additions & 11 deletions src/main/java/com/thealgorithms/maths/HeronsFormula.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,76 @@
package com.thealgorithms.maths;

/**
* Wikipedia for HeronsFormula => https://en.wikipedia.org/wiki/Heron%27s_formula
* Find the area of a triangle using only side lengths
* Heron's Formula implementation for calculating the area of a triangle given
* its three side lengths.
* <p>
* Heron's Formula states that the area of a triangle whose sides have lengths
* a, b, and c is:
* Area = √(s(s - a)(s - b)(s - c))
* where s is the semi-perimeter of the triangle: s = (a + b + c) / 2
* </p>
*
* @see <a href="https://en.wikipedia.org/wiki/Heron%27s_formula">Heron's
* Formula - Wikipedia</a>
* @author satyabarghav
*/

public final class HeronsFormula {

/*
* A function to get the Area of a Triangle using Heron's Formula
* @param s1,s2,s3 => the three sides of the Triangle
* @return area using the formula (√(s(s – s1)(s – s2)(s – s3)))
* here s is called semi-perimeter and it is the half of the perimeter (i.e; s = (s1+s2+s3)/2)
* @author satyabarghav
/**
* Private constructor to prevent instantiation of this utility class.
*/
private HeronsFormula() {
}

/**
* Checks if all three side lengths are positive.
*
* @param a the length of the first side
* @param b the length of the second side
* @param c the length of the third side
* @return true if all sides are positive, false otherwise
*/
private static boolean areAllSidesPositive(final double a, final double b, final double c) {
return a > 0 && b > 0 && c > 0;
}

/**
* Checks if the given side lengths satisfy the triangle inequality theorem.
* <p>
* The triangle inequality theorem states that the sum of any two sides
* of a triangle must be greater than the third side.
* </p>
*
* @param a the length of the first side
* @param b the length of the second side
* @param c the length of the third side
* @return true if the sides can form a valid triangle, false otherwise
*/
private static boolean canFormTriangle(final double a, final double b, final double c) {
return a + b > c && b + c > a && c + a > b;
}

/**
* Calculates the area of a triangle using Heron's Formula.
* <p>
* Given three side lengths a, b, and c, the area is computed as:
* Area = √(s(s - a)(s - b)(s - c))
* where s is the semi-perimeter: s = (a + b + c) / 2
* </p>
*
* @param a the length of the first side (must be positive)
* @param b the length of the second side (must be positive)
* @param c the length of the third side (must be positive)
* @return the area of the triangle
* @throws IllegalArgumentException if any side length is non-positive or if the
* sides cannot form a valid triangle
*/
public static double herons(final double a, final double b, final double c) {
if (!areAllSidesPositive(a, b, c) || !canFormTriangle(a, b, c)) {
throw new IllegalArgumentException("Triangle can't be formed with the given side lengths");
if (!areAllSidesPositive(a, b, c)) {
throw new IllegalArgumentException("All side lengths must be positive");
}
if (!canFormTriangle(a, b, c)) {
throw new IllegalArgumentException("Triangle cannot be formed with the given side lengths (violates triangle inequality)");
}
final double s = (a + b + c) / 2.0;
return Math.sqrt((s) * (s - a) * (s - b) * (s - c));
Expand Down
128 changes: 116 additions & 12 deletions src/test/java/com/thealgorithms/maths/HeronsFormulaTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,141 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class HeronsFormulaTest {
/**
* Test cases for {@link HeronsFormula}.
*/
class HeronsFormulaTest {

private static final double EPSILON = 1e-10;

@Test
void testRightTriangleThreeFourFive() {
Assertions.assertEquals(6.0, HeronsFormula.herons(3, 4, 5), EPSILON);
}

@Test
void testTriangleTwentyFourThirtyEighteen() {
Assertions.assertEquals(216.0, HeronsFormula.herons(24, 30, 18), EPSILON);
}

@Test
void testEquilateralTriangle() {
Assertions.assertEquals(0.4330127018922193, HeronsFormula.herons(1, 1, 1), EPSILON);
}

@Test
void testScaleneTriangleFourFiveEight() {
Assertions.assertEquals(8.181534085976786, HeronsFormula.herons(4, 5, 8), EPSILON);
}

@Test
void testEquilateralTriangleLargeSides() {
final double side = 10.0;
final double expectedArea = Math.sqrt(3) / 4 * side * side;
Assertions.assertEquals(expectedArea, HeronsFormula.herons(side, side, side), EPSILON);
}

@Test
void test1() {
Assertions.assertEquals(HeronsFormula.herons(3, 4, 5), 6.0);
void testIsoscelesTriangle() {
Assertions.assertEquals(12.0, HeronsFormula.herons(5, 5, 6), EPSILON);
}

@Test
void test2() {
Assertions.assertEquals(HeronsFormula.herons(24, 30, 18), 216.0);
void testSmallTriangle() {
Assertions.assertEquals(0.4330127018922193, HeronsFormula.herons(1.0, 1.0, 1.0), EPSILON);
}

@Test
void test3() {
Assertions.assertEquals(HeronsFormula.herons(1, 1, 1), 0.4330127018922193);
void testLargeTriangle() {
Assertions.assertEquals(600.0, HeronsFormula.herons(30, 40, 50), EPSILON);
}

@Test
void test4() {
Assertions.assertEquals(HeronsFormula.herons(4, 5, 8), 8.181534085976786);
void testDecimalSides() {
final double area = HeronsFormula.herons(2.5, 3.5, 4.0);
Assertions.assertTrue(area > 0);
Assertions.assertEquals(4.330127018922194, area, EPSILON);
}

@Test
public void testCalculateAreaWithInvalidInput() {
void testDegenerateTriangleEqualToSumOfOtherTwo() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(1, 2, 3); });
}

@Test
void testDegenerateTriangleVariant2() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(2, 1, 3); });
}

@Test
void testDegenerateTriangleVariant3() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(3, 2, 1); });
}

@Test
void testDegenerateTriangleVariant4() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(1, 3, 2); });
}

Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(1, 1, 0); });
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(1, 0, 1); });
@Test
void testInvalidTriangleSideGreaterThanSum() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(1, 1, 5); });
}

@Test
void testZeroFirstSide() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(0, 1, 1); });
}

@Test
void testZeroSecondSide() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(1, 0, 1); });
}

@Test
void testZeroThirdSide() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(1, 1, 0); });
}

@Test
void testNegativeFirstSide() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(-1, 2, 2); });
}

@Test
void testNegativeSecondSide() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(2, -1, 2); });
}

@Test
void testNegativeThirdSide() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(2, 2, -1); });
}

@Test
void testAllNegativeSides() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(-1, -2, -3); });
}

@Test
void testAllZeroSides() {
Assertions.assertThrows(IllegalArgumentException.class, () -> { HeronsFormula.herons(0, 0, 0); });
}

@Test
void testVerySmallTriangle() {
final double result = HeronsFormula.herons(0.001, 0.001, 0.001);
Assertions.assertTrue(result > 0);
Assertions.assertTrue(result < 0.001);
}

@Test
void testRightTriangleFiveTwelveThirteen() {
Assertions.assertEquals(30.0, HeronsFormula.herons(5, 12, 13), EPSILON);
}

@Test
void testRightTriangleEightFifteenSeventeen() {
Assertions.assertEquals(60.0, HeronsFormula.herons(8, 15, 17), EPSILON);
}
}