Skip to content

Commit b493fec

Browse files
committed
feat: add SociableNumber implementation
1 parent 6fbbc94 commit b493fec

2 files changed

Lines changed: 109 additions & 0 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.thealgorithms.maths;
2+
3+
/**
4+
* Sociable numbers are natural numbers that form a cyclic sequence where the
5+
* sum of proper divisors of each number equals the next number in the sequence,
6+
* with the sequence eventually returning to the starting number.
7+
* Amicable numbers are a special case of sociable numbers with a cycle length of 2.
8+
* Example: (12496, 14288, 15472, 14536, 14264) is a sociable cycle of length 5.
9+
*
10+
* @author Vraj Prajapati (@Rosander0)
11+
* @see <a href="https://en.wikipedia.org/wiki/Sociable_number">Wikipedia: Sociable Number</a>
12+
* @see AmicableNumber
13+
*/
14+
public final class SociableNumber {
15+
16+
private SociableNumber() {
17+
// Utility class
18+
}
19+
20+
static int sumOfProperDivisors(final int number) {
21+
if (number <= 0) {
22+
return 0;
23+
}
24+
int sum = 0;
25+
for (int i = 1; i < number; i++) {
26+
if (number % i == 0) {
27+
sum += i;
28+
}
29+
}
30+
return sum;
31+
}
32+
33+
/**
34+
* Checks whether a number is part of a sociable cycle of a given length.
35+
*
36+
* @param number the starting number (must be positive)
37+
* @param cycleLength the expected cycle length (must be greater than 1)
38+
* @return true if the number is part of a sociable cycle of given length, false otherwise
39+
*/
40+
public static boolean isSociable(final int number, final int cycleLength) {
41+
if (number <= 0 || cycleLength <= 1) {
42+
return false;
43+
}
44+
int current = number;
45+
for (int i = 0; i < cycleLength; i++) {
46+
current = sumOfProperDivisors(current);
47+
if (current == number) {
48+
return i == cycleLength - 1;
49+
}
50+
}
51+
return false;
52+
}
53+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.thealgorithms.maths;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
/**
10+
* Tests for {@link SociableNumber}.
11+
*
12+
* @author Vraj Prajapati (@Rosander0)
13+
*/
14+
public class SociableNumberTest {
15+
16+
@Test
17+
public void testSumOfProperDivisorsEdgeCases() {
18+
assertEquals(0, SociableNumber.sumOfProperDivisors(0));
19+
assertEquals(0, SociableNumber.sumOfProperDivisors(-5));
20+
assertEquals(0, SociableNumber.sumOfProperDivisors(1));
21+
assertEquals(1, SociableNumber.sumOfProperDivisors(2));
22+
}
23+
24+
@Test
25+
public void testSociableCycleOfLengthFive() {
26+
assertTrue(SociableNumber.isSociable(12496, 5));
27+
}
28+
29+
@Test
30+
public void testAmicableNumbersAreSociableOfLengthTwo() {
31+
assertTrue(SociableNumber.isSociable(220, 2));
32+
assertTrue(SociableNumber.isSociable(284, 2));
33+
}
34+
35+
@Test
36+
public void testNonSociableNumbers() {
37+
assertFalse(SociableNumber.isSociable(12, 5));
38+
assertFalse(SociableNumber.isSociable(10, 3));
39+
}
40+
41+
@Test
42+
public void testEarlyCycleReturn() {
43+
// 220 has cycle length 2; requesting a different length should return
44+
// false because it returns to the start too early.
45+
assertFalse(SociableNumber.isSociable(220, 3));
46+
assertFalse(SociableNumber.isSociable(284, 4));
47+
assertFalse(SociableNumber.isSociable(12496, 3));
48+
}
49+
50+
@Test
51+
public void testInvalidInputs() {
52+
assertFalse(SociableNumber.isSociable(0, 5));
53+
assertFalse(SociableNumber.isSociable(-1, 5));
54+
assertFalse(SociableNumber.isSociable(220, 1));
55+
}
56+
}

0 commit comments

Comments
 (0)