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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 45 additions & 16 deletions src/main/java/com/thealgorithms/maths/HarshadNumber.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
140 changes: 125 additions & 15 deletions src/test/java/com/thealgorithms/maths/HarshadNumberTest.java
Original file line number Diff line number Diff line change
@@ -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");
}
}
}