refactor: Enhance docs, code, add tests in HarshadNumber (#6745)

This commit is contained in:
Hardik Pawar
2025-10-15 14:16:17 +05:30
committed by GitHub
parent 219cc33588
commit d62b438fcd
2 changed files with 170 additions and 31 deletions

View File

@@ -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 <a href="https://github.com/Hardvan">Hardvan</a>
* @see <a href="https://en.wikipedia.org/wiki/Harshad_number">Harshad Number -
* Wikipedia</a>
*/
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;

View File

@@ -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
public void harshadNumber() {
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));
assertTrue(HarshadNumber.isHarshad(18));
assertFalse(HarshadNumber.isHarshad(-18));
assertFalse(HarshadNumber.isHarshad(19));
assertTrue(HarshadNumber.isHarshad(999999999));
assertFalse(HarshadNumber.isHarshad(0));
// 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
assertTrue(HarshadNumber.isHarshad("18"));
assertFalse(HarshadNumber.isHarshad("-18"));
assertFalse(HarshadNumber.isHarshad("19"));
assertTrue(HarshadNumber.isHarshad("999999999"));
assertTrue(HarshadNumber.isHarshad("99999999999100"));
// 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
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
}
@Test
void testZeroThrowsException() {
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(0));
}
@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");
}
}
}