diff --git a/src/main/java/com/thealgorithms/maths/HarshadNumber.java b/src/main/java/com/thealgorithms/maths/HarshadNumber.java index 5792e925a8aa..abe21cb045ae 100644 --- a/src/main/java/com/thealgorithms/maths/HarshadNumber.java +++ b/src/main/java/com/thealgorithms/maths/HarshadNumber.java @@ -1,49 +1,78 @@ package com.thealgorithms.maths; -// Wikipedia for Harshad Number : https://en.wikipedia.org/wiki/Harshad_number - +/** + * A Harshad number (or Niven number) in a given number base is an integer that + * is divisible by the sum of its digits. + * For example, 18 is a Harshad number because 18 is divisible by (1 + 8) = 9. + * The name "Harshad" comes from the Sanskrit words "harį¹£a" (joy) and "da" + * (give), meaning "joy-giver". + * + * @author Hardvan + * @see Harshad Number - + * Wikipedia + */ public final class HarshadNumber { private HarshadNumber() { } /** - * A function to check if a number is Harshad number or not + * Checks if a number is a Harshad number. + * A Harshad number is a positive integer that is divisible by the sum of its + * digits. * - * @param n The number to be checked - * @return {@code true} if {@code a} is Harshad number, otherwise + * @param n the number to be checked (must be positive) + * @return {@code true} if {@code n} is a Harshad number, otherwise * {@code false} + * @throws IllegalArgumentException if {@code n} is less than or equal to 0 */ public static boolean isHarshad(long n) { if (n <= 0) { - return false; + throw new IllegalArgumentException("Input must be a positive integer. Received: " + n); } - long t = n; + long temp = n; long sumOfDigits = 0; - while (t > 0) { - sumOfDigits += t % 10; - t /= 10; + while (temp > 0) { + sumOfDigits += temp % 10; + temp /= 10; } return n % sumOfDigits == 0; } /** - * A function to check if a number is Harshad number or not + * Checks if a number represented as a string is a Harshad number. + * A Harshad number is a positive integer that is divisible by the sum of its + * digits. * - * @param s The number in String to be checked - * @return {@code true} if {@code a} is Harshad number, otherwise + * @param s the string representation of the number to be checked + * @return {@code true} if the number is a Harshad number, otherwise * {@code false} + * @throws IllegalArgumentException if {@code s} is null, empty, or represents a + * non-positive integer + * @throws NumberFormatException if {@code s} cannot be parsed as a long */ public static boolean isHarshad(String s) { - final Long n = Long.valueOf(s); + if (s == null || s.isEmpty()) { + throw new IllegalArgumentException("Input string cannot be null or empty"); + } + + final long n; + try { + n = Long.parseLong(s); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Input string must be a valid integer: " + s, e); + } + if (n <= 0) { - return false; + throw new IllegalArgumentException("Input must be a positive integer. Received: " + n); } int sumOfDigits = 0; for (char ch : s.toCharArray()) { - sumOfDigits += ch - '0'; + if (Character.isDigit(ch)) { + sumOfDigits += ch - '0'; + } } return n % sumOfDigits == 0; diff --git a/src/test/java/com/thealgorithms/maths/HarshadNumberTest.java b/src/test/java/com/thealgorithms/maths/HarshadNumberTest.java index af1c459f3d7f..299e6bd78a99 100644 --- a/src/test/java/com/thealgorithms/maths/HarshadNumberTest.java +++ b/src/test/java/com/thealgorithms/maths/HarshadNumberTest.java @@ -1,25 +1,135 @@ package com.thealgorithms.maths; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class HarshadNumberTest { +/** + * Test class for {@link HarshadNumber}. + * Tests various scenarios including positive cases, edge cases, and exception + * handling. + */ +class HarshadNumberTest { + + @Test + void testValidHarshadNumbers() { + // Single digit Harshad numbers (all single digits except 0 are Harshad numbers) + Assertions.assertTrue(HarshadNumber.isHarshad(1)); + Assertions.assertTrue(HarshadNumber.isHarshad(2)); + Assertions.assertTrue(HarshadNumber.isHarshad(3)); + Assertions.assertTrue(HarshadNumber.isHarshad(4)); + Assertions.assertTrue(HarshadNumber.isHarshad(5)); + Assertions.assertTrue(HarshadNumber.isHarshad(6)); + Assertions.assertTrue(HarshadNumber.isHarshad(7)); + Assertions.assertTrue(HarshadNumber.isHarshad(8)); + Assertions.assertTrue(HarshadNumber.isHarshad(9)); + + // Two digit Harshad numbers + Assertions.assertTrue(HarshadNumber.isHarshad(10)); // 10 / (1 + 0) = 10 + Assertions.assertTrue(HarshadNumber.isHarshad(12)); // 12 / (1 + 2) = 4 + Assertions.assertTrue(HarshadNumber.isHarshad(18)); // 18 / (1 + 8) = 2 + Assertions.assertTrue(HarshadNumber.isHarshad(20)); // 20 / (2 + 0) = 10 + Assertions.assertTrue(HarshadNumber.isHarshad(21)); // 21 / (2 + 1) = 7 + + // Three digit Harshad numbers + Assertions.assertTrue(HarshadNumber.isHarshad(100)); // 100 / (1 + 0 + 0) = 100 + Assertions.assertTrue(HarshadNumber.isHarshad(102)); // 102 / (1 + 0 + 2) = 34 + Assertions.assertTrue(HarshadNumber.isHarshad(108)); // 108 / (1 + 0 + 8) = 12 + + // Large Harshad numbers + Assertions.assertTrue(HarshadNumber.isHarshad(1000)); // 1000 / (1 + 0 + 0 + 0) = 1000 + Assertions.assertTrue(HarshadNumber.isHarshad(1002)); // 1002 / (1 + 0 + 0 + 2) = 334 + Assertions.assertTrue(HarshadNumber.isHarshad(999999999)); // 999999999 / (9*9) = 12345679 + } @Test - public void harshadNumber() { + void testInvalidHarshadNumbers() { + // Numbers that are not Harshad numbers + Assertions.assertFalse(HarshadNumber.isHarshad(11)); // 11 / (1 + 1) = 5.5 + Assertions.assertFalse(HarshadNumber.isHarshad(13)); // 13 / (1 + 3) = 3.25 + Assertions.assertFalse(HarshadNumber.isHarshad(17)); // 17 / (1 + 7) = 2.125 + Assertions.assertFalse(HarshadNumber.isHarshad(19)); // 19 / (1 + 9) = 1.9 + Assertions.assertFalse(HarshadNumber.isHarshad(23)); // 23 / (2 + 3) = 4.6 + Assertions.assertFalse(HarshadNumber.isHarshad(101)); // 101 / (1 + 0 + 1) = 50.5 + } - assertTrue(HarshadNumber.isHarshad(18)); - assertFalse(HarshadNumber.isHarshad(-18)); - assertFalse(HarshadNumber.isHarshad(19)); - assertTrue(HarshadNumber.isHarshad(999999999)); - assertFalse(HarshadNumber.isHarshad(0)); + @Test + void testZeroThrowsException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(0)); + } - assertTrue(HarshadNumber.isHarshad("18")); - assertFalse(HarshadNumber.isHarshad("-18")); - assertFalse(HarshadNumber.isHarshad("19")); - assertTrue(HarshadNumber.isHarshad("999999999")); - assertTrue(HarshadNumber.isHarshad("99999999999100")); + @Test + void testNegativeNumbersThrowException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(-1)); + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(-18)); + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(-100)); + } + + @Test + void testValidHarshadNumbersWithString() { + // Single digit Harshad numbers + Assertions.assertTrue(HarshadNumber.isHarshad("1")); + Assertions.assertTrue(HarshadNumber.isHarshad("2")); + Assertions.assertTrue(HarshadNumber.isHarshad("9")); + + // Two digit Harshad numbers + Assertions.assertTrue(HarshadNumber.isHarshad("10")); + Assertions.assertTrue(HarshadNumber.isHarshad("12")); + Assertions.assertTrue(HarshadNumber.isHarshad("18")); + + // Large Harshad numbers + Assertions.assertTrue(HarshadNumber.isHarshad("1000")); + Assertions.assertTrue(HarshadNumber.isHarshad("999999999")); + Assertions.assertTrue(HarshadNumber.isHarshad("99999999999100")); + } + + @Test + void testInvalidHarshadNumbersWithString() { + // Numbers that are not Harshad numbers + Assertions.assertFalse(HarshadNumber.isHarshad("11")); + Assertions.assertFalse(HarshadNumber.isHarshad("13")); + Assertions.assertFalse(HarshadNumber.isHarshad("19")); + Assertions.assertFalse(HarshadNumber.isHarshad("23")); + } + + @Test + void testStringWithZeroThrowsException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("0")); + } + + @Test + void testStringWithNegativeNumbersThrowsException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("-1")); + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("-18")); + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("-100")); + } + + @Test + void testNullStringThrowsException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(null)); + } + + @Test + void testEmptyStringThrowsException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("")); + } + + @Test + void testInvalidStringThrowsException() { + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("abc")); + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("12.5")); + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("12a")); + Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(" 12 ")); + } + + @Test + void testMaxLongValue() { + // Test with a large number close to Long.MAX_VALUE + long largeHarshadCandidate = 9223372036854775800L; + // This specific number may or may not be Harshad, just testing it doesn't crash + try { + HarshadNumber.isHarshad(largeHarshadCandidate); + } catch (Exception e) { + Assertions.fail("Should not throw exception for valid large numbers"); + } } }