Skip to content

AmicableNumber refactoring #4263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,7 @@
* [NextFitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/NextFitTest.java)
* [PasswordGenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/PasswordGenTest.java)
* [SieveOfEratosthenesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SieveOfEratosthenesTest.java)
* [StackPostfixNotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/StackPostfixNotationTest.java)
* [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java)
* [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java)
* [UniquePathsTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/UniquePathsTests.java)
Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>

<build>
Expand Down
94 changes: 41 additions & 53 deletions src/main/java/com/thealgorithms/maths/AmicableNumber.java
Original file line number Diff line number Diff line change
@@ -1,81 +1,69 @@
package com.thealgorithms.maths;

import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;

/**
* Amicable numbers are two different numbers so related that the sum of the
* proper divisors of each is equal to the other number. (A proper divisor of a
* number is a positive factor of that number other than the number itself. For
* example, the proper divisors of 6 are 1, 2, and 3.) A pair of amicable
* numbers constitutes an aliquot sequence of period 2. It is unknown if there
* are infinitely many pairs of amicable numbers. *
* Amicable numbers are two different natural numbers that the sum of the
* proper divisors of each is equal to the other number.
* (A proper divisor of a number is a positive factor of that number other than the number itself.
* For example, the proper divisors of 6 are 1, 2, and 3.)
* A pair of amicable numbers constitutes an aliquot sequence of period 2.
* It is unknown if there are infinitely many pairs of amicable numbers.
*
* <p>
* link: https://en.wikipedia.org/wiki/Amicable_numbers *
*
* link: https://en.wikipedia.org/wiki/Amicable_numbers
* <p>
* Simple Example : (220,284) 220 is divisible by {1,2,4,5,10,11,20,22,44,55,110
* } <- Sum = 284
* 284 is divisible by -> 1,2,4,71,142 and the Sum of that is. Yes right you
* probably expected it 220
* Simple Example : (220, 284)
* 220 is divisible by {1,2,4,5,10,11,20,22,44,55,110} <- SUM = 284
* 284 is divisible by {1,2,4,71,142} <- SUM = 220.
*/
public class AmicableNumber {

public static void main(String[] args) {
AmicableNumber.findAllInRange(1, 3000);
/* Res -> Int Range of 1 till 3000there are 3Amicable_numbers These are 1: = ( 220,284)
2: = ( 1184,1210) 3: = ( 2620,2924) So it worked */
}

/**
* @param startValue
* @param stopValue
* @return
* Finds all the amicable numbers in a given range.
*
* @param from range start value
* @param to range end value (inclusive)
* @return list with amicable numbers found in given range.
*/
static void findAllInRange(int startValue, int stopValue) {
/* the 2 for loops are to avoid to double check tuple. For example (200,100) and (100,200)
* is the same calculation also to avoid is to check the number with it self. a number with
* itself is always a AmicableNumber
* */
StringBuilder res = new StringBuilder();
int countofRes = 0;
public static Set<Pair<Integer, Integer>> findAllInRange(int from, int to) {
if (from <= 0 || to <= 0 || to < from) {
throw new IllegalArgumentException("Given range of values is invalid!");
}

Set<Pair<Integer, Integer>> result = new LinkedHashSet<>();

for (int i = startValue; i < stopValue; i++) {
for (int j = i + 1; j <= stopValue; j++) {
for (int i = from; i < to; i++) {
for (int j = i + 1; j <= to; j++) {
if (isAmicableNumber(i, j)) {
countofRes++;
res.append("" + countofRes + ": = ( " + i + "," + j + ")"
+ "\t");
result.add(Pair.of(i, j));
}
}
}
res.insert(0, "Int Range of " + startValue + " till " + stopValue + " there are " + countofRes + " Amicable_numbers.These are \n ");
System.out.println(res);
return result;
}

/**
* Check if {@code numberOne and numberTwo } are AmicableNumbers or not
*
* @param numberOne numberTwo
* @return {@code true} if {@code numberOne numberTwo} isAmicableNumbers
* otherwise false
* Checks whether 2 numbers are AmicableNumbers or not.
*/
static boolean isAmicableNumber(int numberOne, int numberTwo) {
return ((recursiveCalcOfDividerSum(numberOne, numberOne) == numberTwo && numberOne == recursiveCalcOfDividerSum(numberTwo, numberTwo)));
public static boolean isAmicableNumber(int a, int b) {
if (a <= 0 || b <= 0) {
throw new IllegalArgumentException("Input numbers must be natural!");
}
return sumOfDividers(a, a) == b && sumOfDividers(b, b) == a;
}

/**
* calculated in recursive calls the Sum of all the Dividers beside it self
*
* @param number div = the next to test dividely by using the modulo
* operator
* @return sum of all the dividers
* Recursively calculates the sum of all dividers for a given number excluding the divider itself.
*/
static int recursiveCalcOfDividerSum(int number, int div) {
if (div == 1) {
private static int sumOfDividers(int number, int divisor) {
if (divisor == 1) {
return 0;
} else if (number % --div == 0) {
return recursiveCalcOfDividerSum(number, div) + div;
} else if (number % --divisor == 0) {
return sumOfDividers(number, divisor) + divisor;
} else {
return recursiveCalcOfDividerSum(number, div);
return sumOfDividers(number, divisor);
}
}
}
45 changes: 44 additions & 1 deletion src/test/java/com/thealgorithms/maths/AmicableNumberTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,57 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class AmicableNumberTest {
private static final String INVALID_RANGE_EXCEPTION_MESSAGE = "Given range of values is invalid!";
private static final String INVALID_NUMBERS_EXCEPTION_MESSAGE = "Input numbers must be natural!";

@Test
void testAmicableNumber() {
public void testShouldThrowExceptionWhenInvalidRangeProvided() {
checkInvalidRange(0, 0);
checkInvalidRange(0, 1);
checkInvalidRange(1, 0);
checkInvalidRange(10, -1);
checkInvalidRange(-1, 10);
}

@Test
public void testShouldThrowExceptionWhenInvalidNumbersProvided() {
checkInvalidNumbers(0, 0);
checkInvalidNumbers(0, 1);
checkInvalidNumbers(1, 0);
}

@Test
public void testAmicableNumbers() {
assertThat(AmicableNumber.isAmicableNumber(220, 284)).isTrue();
assertThat(AmicableNumber.isAmicableNumber(1184, 1210)).isTrue();
assertThat(AmicableNumber.isAmicableNumber(2620, 2924)).isTrue();
}

@Test
public void testShouldFindAllAmicableNumbersInRange() {
// given
var expectedResult = Set.of(Pair.of(220, 284), Pair.of(1184, 1210), Pair.of(2620, 2924));

// when
Set<Pair<Integer, Integer>> result = AmicableNumber.findAllInRange(1, 3000);

// then
Assertions.assertTrue(result.containsAll(expectedResult));
}

private static void checkInvalidRange(int from, int to) {
IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> AmicableNumber.findAllInRange(from, to));
Assertions.assertEquals(exception.getMessage(), INVALID_RANGE_EXCEPTION_MESSAGE);
}

private static void checkInvalidNumbers(int a, int b) {
IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> AmicableNumber.isAmicableNumber(a, b));
Assertions.assertEquals(exception.getMessage(), INVALID_NUMBERS_EXCEPTION_MESSAGE);
}
}