Skip to content

Commit d62b438

Browse files
authored
refactor: Enhance docs, code, add tests in HarshadNumber (TheAlgorithms#6745)
1 parent 219cc33 commit d62b438

File tree

2 files changed

+170
-31
lines changed

2 files changed

+170
-31
lines changed

src/main/java/com/thealgorithms/maths/HarshadNumber.java

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,78 @@
11
package com.thealgorithms.maths;
22

3-
// Wikipedia for Harshad Number : https://en.wikipedia.org/wiki/Harshad_number
4-
3+
/**
4+
* A Harshad number (or Niven number) in a given number base is an integer that
5+
* is divisible by the sum of its digits.
6+
* For example, 18 is a Harshad number because 18 is divisible by (1 + 8) = 9.
7+
* The name "Harshad" comes from the Sanskrit words "harṣa" (joy) and "da"
8+
* (give), meaning "joy-giver".
9+
*
10+
* @author <a href="https://github.com/Hardvan">Hardvan</a>
11+
* @see <a href="https://en.wikipedia.org/wiki/Harshad_number">Harshad Number -
12+
* Wikipedia</a>
13+
*/
514
public final class HarshadNumber {
615
private HarshadNumber() {
716
}
817

918
/**
10-
* A function to check if a number is Harshad number or not
19+
* Checks if a number is a Harshad number.
20+
* A Harshad number is a positive integer that is divisible by the sum of its
21+
* digits.
1122
*
12-
* @param n The number to be checked
13-
* @return {@code true} if {@code a} is Harshad number, otherwise
23+
* @param n the number to be checked (must be positive)
24+
* @return {@code true} if {@code n} is a Harshad number, otherwise
1425
* {@code false}
26+
* @throws IllegalArgumentException if {@code n} is less than or equal to 0
1527
*/
1628
public static boolean isHarshad(long n) {
1729
if (n <= 0) {
18-
return false;
30+
throw new IllegalArgumentException("Input must be a positive integer. Received: " + n);
1931
}
2032

21-
long t = n;
33+
long temp = n;
2234
long sumOfDigits = 0;
23-
while (t > 0) {
24-
sumOfDigits += t % 10;
25-
t /= 10;
35+
while (temp > 0) {
36+
sumOfDigits += temp % 10;
37+
temp /= 10;
2638
}
2739

2840
return n % sumOfDigits == 0;
2941
}
3042

3143
/**
32-
* A function to check if a number is Harshad number or not
44+
* Checks if a number represented as a string is a Harshad number.
45+
* A Harshad number is a positive integer that is divisible by the sum of its
46+
* digits.
3347
*
34-
* @param s The number in String to be checked
35-
* @return {@code true} if {@code a} is Harshad number, otherwise
48+
* @param s the string representation of the number to be checked
49+
* @return {@code true} if the number is a Harshad number, otherwise
3650
* {@code false}
51+
* @throws IllegalArgumentException if {@code s} is null, empty, or represents a
52+
* non-positive integer
53+
* @throws NumberFormatException if {@code s} cannot be parsed as a long
3754
*/
3855
public static boolean isHarshad(String s) {
39-
final Long n = Long.valueOf(s);
56+
if (s == null || s.isEmpty()) {
57+
throw new IllegalArgumentException("Input string cannot be null or empty");
58+
}
59+
60+
final long n;
61+
try {
62+
n = Long.parseLong(s);
63+
} catch (NumberFormatException e) {
64+
throw new IllegalArgumentException("Input string must be a valid integer: " + s, e);
65+
}
66+
4067
if (n <= 0) {
41-
return false;
68+
throw new IllegalArgumentException("Input must be a positive integer. Received: " + n);
4269
}
4370

4471
int sumOfDigits = 0;
4572
for (char ch : s.toCharArray()) {
46-
sumOfDigits += ch - '0';
73+
if (Character.isDigit(ch)) {
74+
sumOfDigits += ch - '0';
75+
}
4776
}
4877

4978
return n % sumOfDigits == 0;
Lines changed: 125 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,135 @@
11
package com.thealgorithms.maths;
22

3-
import static org.junit.jupiter.api.Assertions.assertFalse;
4-
import static org.junit.jupiter.api.Assertions.assertTrue;
5-
3+
import org.junit.jupiter.api.Assertions;
64
import org.junit.jupiter.api.Test;
75

8-
public class HarshadNumberTest {
6+
/**
7+
* Test class for {@link HarshadNumber}.
8+
* Tests various scenarios including positive cases, edge cases, and exception
9+
* handling.
10+
*/
11+
class HarshadNumberTest {
12+
13+
@Test
14+
void testValidHarshadNumbers() {
15+
// Single digit Harshad numbers (all single digits except 0 are Harshad numbers)
16+
Assertions.assertTrue(HarshadNumber.isHarshad(1));
17+
Assertions.assertTrue(HarshadNumber.isHarshad(2));
18+
Assertions.assertTrue(HarshadNumber.isHarshad(3));
19+
Assertions.assertTrue(HarshadNumber.isHarshad(4));
20+
Assertions.assertTrue(HarshadNumber.isHarshad(5));
21+
Assertions.assertTrue(HarshadNumber.isHarshad(6));
22+
Assertions.assertTrue(HarshadNumber.isHarshad(7));
23+
Assertions.assertTrue(HarshadNumber.isHarshad(8));
24+
Assertions.assertTrue(HarshadNumber.isHarshad(9));
25+
26+
// Two digit Harshad numbers
27+
Assertions.assertTrue(HarshadNumber.isHarshad(10)); // 10 / (1 + 0) = 10
28+
Assertions.assertTrue(HarshadNumber.isHarshad(12)); // 12 / (1 + 2) = 4
29+
Assertions.assertTrue(HarshadNumber.isHarshad(18)); // 18 / (1 + 8) = 2
30+
Assertions.assertTrue(HarshadNumber.isHarshad(20)); // 20 / (2 + 0) = 10
31+
Assertions.assertTrue(HarshadNumber.isHarshad(21)); // 21 / (2 + 1) = 7
32+
33+
// Three digit Harshad numbers
34+
Assertions.assertTrue(HarshadNumber.isHarshad(100)); // 100 / (1 + 0 + 0) = 100
35+
Assertions.assertTrue(HarshadNumber.isHarshad(102)); // 102 / (1 + 0 + 2) = 34
36+
Assertions.assertTrue(HarshadNumber.isHarshad(108)); // 108 / (1 + 0 + 8) = 12
37+
38+
// Large Harshad numbers
39+
Assertions.assertTrue(HarshadNumber.isHarshad(1000)); // 1000 / (1 + 0 + 0 + 0) = 1000
40+
Assertions.assertTrue(HarshadNumber.isHarshad(1002)); // 1002 / (1 + 0 + 0 + 2) = 334
41+
Assertions.assertTrue(HarshadNumber.isHarshad(999999999)); // 999999999 / (9*9) = 12345679
42+
}
943

1044
@Test
11-
public void harshadNumber() {
45+
void testInvalidHarshadNumbers() {
46+
// Numbers that are not Harshad numbers
47+
Assertions.assertFalse(HarshadNumber.isHarshad(11)); // 11 / (1 + 1) = 5.5
48+
Assertions.assertFalse(HarshadNumber.isHarshad(13)); // 13 / (1 + 3) = 3.25
49+
Assertions.assertFalse(HarshadNumber.isHarshad(17)); // 17 / (1 + 7) = 2.125
50+
Assertions.assertFalse(HarshadNumber.isHarshad(19)); // 19 / (1 + 9) = 1.9
51+
Assertions.assertFalse(HarshadNumber.isHarshad(23)); // 23 / (2 + 3) = 4.6
52+
Assertions.assertFalse(HarshadNumber.isHarshad(101)); // 101 / (1 + 0 + 1) = 50.5
53+
}
1254

13-
assertTrue(HarshadNumber.isHarshad(18));
14-
assertFalse(HarshadNumber.isHarshad(-18));
15-
assertFalse(HarshadNumber.isHarshad(19));
16-
assertTrue(HarshadNumber.isHarshad(999999999));
17-
assertFalse(HarshadNumber.isHarshad(0));
55+
@Test
56+
void testZeroThrowsException() {
57+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(0));
58+
}
1859

19-
assertTrue(HarshadNumber.isHarshad("18"));
20-
assertFalse(HarshadNumber.isHarshad("-18"));
21-
assertFalse(HarshadNumber.isHarshad("19"));
22-
assertTrue(HarshadNumber.isHarshad("999999999"));
23-
assertTrue(HarshadNumber.isHarshad("99999999999100"));
60+
@Test
61+
void testNegativeNumbersThrowException() {
62+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(-1));
63+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(-18));
64+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(-100));
65+
}
66+
67+
@Test
68+
void testValidHarshadNumbersWithString() {
69+
// Single digit Harshad numbers
70+
Assertions.assertTrue(HarshadNumber.isHarshad("1"));
71+
Assertions.assertTrue(HarshadNumber.isHarshad("2"));
72+
Assertions.assertTrue(HarshadNumber.isHarshad("9"));
73+
74+
// Two digit Harshad numbers
75+
Assertions.assertTrue(HarshadNumber.isHarshad("10"));
76+
Assertions.assertTrue(HarshadNumber.isHarshad("12"));
77+
Assertions.assertTrue(HarshadNumber.isHarshad("18"));
78+
79+
// Large Harshad numbers
80+
Assertions.assertTrue(HarshadNumber.isHarshad("1000"));
81+
Assertions.assertTrue(HarshadNumber.isHarshad("999999999"));
82+
Assertions.assertTrue(HarshadNumber.isHarshad("99999999999100"));
83+
}
84+
85+
@Test
86+
void testInvalidHarshadNumbersWithString() {
87+
// Numbers that are not Harshad numbers
88+
Assertions.assertFalse(HarshadNumber.isHarshad("11"));
89+
Assertions.assertFalse(HarshadNumber.isHarshad("13"));
90+
Assertions.assertFalse(HarshadNumber.isHarshad("19"));
91+
Assertions.assertFalse(HarshadNumber.isHarshad("23"));
92+
}
93+
94+
@Test
95+
void testStringWithZeroThrowsException() {
96+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("0"));
97+
}
98+
99+
@Test
100+
void testStringWithNegativeNumbersThrowsException() {
101+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("-1"));
102+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("-18"));
103+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("-100"));
104+
}
105+
106+
@Test
107+
void testNullStringThrowsException() {
108+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(null));
109+
}
110+
111+
@Test
112+
void testEmptyStringThrowsException() {
113+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(""));
114+
}
115+
116+
@Test
117+
void testInvalidStringThrowsException() {
118+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("abc"));
119+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("12.5"));
120+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad("12a"));
121+
Assertions.assertThrows(IllegalArgumentException.class, () -> HarshadNumber.isHarshad(" 12 "));
122+
}
123+
124+
@Test
125+
void testMaxLongValue() {
126+
// Test with a large number close to Long.MAX_VALUE
127+
long largeHarshadCandidate = 9223372036854775800L;
128+
// This specific number may or may not be Harshad, just testing it doesn't crash
129+
try {
130+
HarshadNumber.isHarshad(largeHarshadCandidate);
131+
} catch (Exception e) {
132+
Assertions.fail("Should not throw exception for valid large numbers");
133+
}
24134
}
25135
}

0 commit comments

Comments
 (0)