Skip to content

Commit e788111

Browse files
Dev: Added Germain and Safe prime utility class (TheAlgorithms#6611)
* feat: add Germain and Safe prime utility class with unit tests * refactor the code * fixed identified bugs * fixed identified remaining bugs --------- Co-authored-by: Deniz Altunkapan <[email protected]>
1 parent 16557a9 commit e788111

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.thealgorithms.maths;
2+
3+
import com.thealgorithms.maths.Prime.PrimeCheck;
4+
5+
/**
6+
* A utility class to check whether a number is a Germain prime or a Safe prime.
7+
*
8+
* <p>This class provides methods to:
9+
* <ul>
10+
* <li>Check if a number is a Germain prime</li>
11+
* <li>Check if a number is a Safe prime</li>
12+
* </ul>
13+
*
14+
* <p>Definitions:
15+
* <ul>
16+
* <li>A Germain prime is a prime number p such that 2p + 1 is also prime.</li>
17+
* <li>A Safe prime is a prime number p such that (p - 1) / 2 is also prime.</li>
18+
* </ul>
19+
*
20+
* <p>This class is final and cannot be instantiated.
21+
*
22+
* @see <a href="https://en.wikipedia.org/wiki/Safe_and_Sophie_Germain_primes">Wikipedia: Safe and Sophie Germain primes</a>
23+
*/
24+
public final class GermainPrimeAndSafePrime {
25+
26+
// Private constructor to prevent instantiation
27+
private GermainPrimeAndSafePrime() {
28+
}
29+
30+
/**
31+
* Checks if a number is a Germain prime.
32+
*
33+
* <p>A Germain prime is a prime number p such that 2p + 1 is also prime.
34+
*
35+
* @param number the number to check; must be a positive integer
36+
* @return {@code true} if the number is a Germain prime, {@code false} otherwise
37+
* @throws IllegalArgumentException if the input number is less than 1
38+
*/
39+
public static boolean isGermainPrime(int number) {
40+
if (number < 1) {
41+
throw new IllegalArgumentException("Input value must be a positive integer. Input value: " + number);
42+
}
43+
// A number is a Germain prime if it is prime and 2 * number + 1 is also prime
44+
return PrimeCheck.isPrime(number) && PrimeCheck.isPrime(2 * number + 1);
45+
}
46+
47+
/**
48+
* Checks if a number is a Safe prime.
49+
*
50+
* <p>A Safe prime is a prime number p such that (p - 1) / 2 is also prime.
51+
*
52+
* @param number the number to check; must be a positive integer
53+
* @return {@code true} if the number is a Safe prime, {@code false} otherwise
54+
* @throws IllegalArgumentException if the input number is less than 1
55+
*/
56+
public static boolean isSafePrime(int number) {
57+
if (number < 1) {
58+
throw new IllegalArgumentException("Input value must be a positive integer. Input value: " + number);
59+
}
60+
// A number is a Safe prime if it is prime, (number - 1) is even, and (number - 1) / 2 is prime
61+
return ((number - 1) % 2 == 0) && PrimeCheck.isPrime(number) && PrimeCheck.isPrime((number - 1) / 2);
62+
}
63+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.thealgorithms.maths;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import java.util.stream.Stream;
7+
import org.junit.jupiter.api.DisplayName;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.Arguments;
10+
import org.junit.jupiter.params.provider.MethodSource;
11+
12+
class GermainPrimeAndSafePrimeTest {
13+
14+
static Stream<Arguments> provideNumbersForGermainPrimes() {
15+
return Stream.of(Arguments.of(2, Boolean.TRUE), Arguments.of(3, Boolean.TRUE), Arguments.of(5, Boolean.TRUE), Arguments.of(11, Boolean.TRUE), Arguments.of(23, Boolean.TRUE), Arguments.of(293, Boolean.TRUE), Arguments.of(4, Boolean.FALSE), Arguments.of(7, Boolean.FALSE),
16+
Arguments.of(9, Boolean.FALSE), Arguments.of(1, Boolean.FALSE));
17+
}
18+
19+
static Stream<Arguments> provideNumbersForSafePrimes() {
20+
return Stream.of(Arguments.of(5, Boolean.TRUE), Arguments.of(7, Boolean.TRUE), Arguments.of(11, Boolean.TRUE), Arguments.of(23, Boolean.TRUE), Arguments.of(1283, Boolean.TRUE), Arguments.of(4, Boolean.FALSE), Arguments.of(13, Boolean.FALSE), Arguments.of(9, Boolean.FALSE),
21+
Arguments.of(1, Boolean.FALSE));
22+
}
23+
24+
static Stream<Integer> provideNegativeNumbers() {
25+
return Stream.of(-10, -1, 0);
26+
}
27+
28+
@ParameterizedTest
29+
@MethodSource("provideNumbersForGermainPrimes")
30+
@DisplayName("Check whether a number is a Germain prime")
31+
void testValidGermainPrimes(int number, boolean expected) {
32+
assertEquals(expected, GermainPrimeAndSafePrime.isGermainPrime(number));
33+
}
34+
35+
@ParameterizedTest
36+
@MethodSource("provideNumbersForSafePrimes")
37+
@DisplayName("Check whether a number is a Safe prime")
38+
void testValidSafePrimes(int number, boolean expected) {
39+
assertEquals(expected, GermainPrimeAndSafePrime.isSafePrime(number));
40+
}
41+
42+
@ParameterizedTest
43+
@MethodSource("provideNegativeNumbers")
44+
@DisplayName("Negative numbers and zero should throw IllegalArgumentException")
45+
void testNegativeNumbersThrowException(int number) {
46+
assertThrows(IllegalArgumentException.class, () -> GermainPrimeAndSafePrime.isGermainPrime(number));
47+
assertThrows(IllegalArgumentException.class, () -> GermainPrimeAndSafePrime.isSafePrime(number));
48+
}
49+
}

0 commit comments

Comments
 (0)