From 7edeb43ed1833e9b01e91d629fe920771aac96f8 Mon Sep 17 00:00:00 2001 From: alexyang Date: Fri, 5 Apr 2024 22:17:28 +0800 Subject: [PATCH] BAEL-7598 Check if a number is a perfect number (#16039) * BAEL-7598 Check if a number is a perfect number * add stream based method. refactor UT * refactor UT using bdd style * removes public modifier * add jmh benchmark * use properties and remove uncessary configuration --------- Co-authored-by: alexyang Co-authored-by: travel2china <163321917+travel2china@users.noreply.github.com> --- .../algorithms-miscellaneous-7/pom.xml | 18 +++++ .../perfectnumber/PerfectNumber.java | 50 ++++++++++++++ .../perfectnumber/PerfectNumberBenchmark.java | 41 +++++++++++ .../perfectnumber/PerfectNumberUnitTest.java | 68 +++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumber.java create mode 100644 algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumberBenchmark.java create mode 100644 algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/perfectnumber/PerfectNumberUnitTest.java diff --git a/algorithms-modules/algorithms-miscellaneous-7/pom.xml b/algorithms-modules/algorithms-miscellaneous-7/pom.xml index 3703ea5a16..c520eb6c25 100644 --- a/algorithms-modules/algorithms-miscellaneous-7/pom.xml +++ b/algorithms-modules/algorithms-miscellaneous-7/pom.xml @@ -13,4 +13,22 @@ 1.0.0-SNAPSHOT + + 1.35 + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumber.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumber.java new file mode 100644 index 0000000000..59b7e51a37 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumber.java @@ -0,0 +1,50 @@ +package com.baeldung.algorithms.perfectnumber; + +import java.util.stream.IntStream; + +class PerfectNumber { + + public static boolean isPerfectBruteForce(int number) { + int sum = 0; + for (int i = 1; i <= number / 2; i++) { + if (number % i == 0) { + sum += i; + } + } + return sum == number; + } + + public static boolean isPerfectStream(int number) { + int sum = IntStream.rangeClosed(2, (int) Math.sqrt(number)) + .filter(test -> number % test == 0) + .reduce(1, (s, test) -> s + test + (number / test)); + return sum == number; + } + + public static boolean isPerfectEuclidEuler(int number) { + int p = 2; + int perfectNumber = (int) (Math.pow(2, p - 1) * (Math.pow(2, p) - 1)); + while (perfectNumber <= number) { + if (perfectNumber == number) { + return true; + } + p++; + perfectNumber = (int) (Math.pow(2, p - 1) * (Math.pow(2, p) - 1)); + } + return false; + } + + public static boolean isPerfectEuclidEulerUsingShift(int number) { + int p = 2; + int perfectNumber = (2 << (p - 1)) * ((2 << p) - 1); + while (perfectNumber <= number) { + if (perfectNumber == number) { + return true; + } + p++; + perfectNumber = (2 << (p - 1)) * ((2 << p) - 1); + } + return false; + } + +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumberBenchmark.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumberBenchmark.java new file mode 100644 index 0000000000..9890c2887f --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/perfectnumber/PerfectNumberBenchmark.java @@ -0,0 +1,41 @@ +package com.baeldung.algorithms.perfectnumber; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +public class PerfectNumberBenchmark { + + @Benchmark + public boolean bruteForceBenchmark() { + return PerfectNumber.isPerfectBruteForce(33550336); + } + + @Benchmark + public boolean streamBenchmark() { + return PerfectNumber.isPerfectStream(33550336); + } + + @Benchmark + public boolean euclidEulerBenchmark() { + return PerfectNumber.isPerfectEuclidEuler(33550336); + } + + @Benchmark + public boolean euclidEulerUsingShiftBenchmark() { + return PerfectNumber.isPerfectEuclidEulerUsingShift(33550336); + } + + public static void main(String[] args) throws Exception { + Options options = new OptionsBuilder() + .include(PerfectNumberBenchmark.class.getSimpleName()) + .forks(1) + .build(); + + new Runner(options).run(); + } +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/perfectnumber/PerfectNumberUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/perfectnumber/PerfectNumberUnitTest.java new file mode 100644 index 0000000000..e03e7c8653 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/perfectnumber/PerfectNumberUnitTest.java @@ -0,0 +1,68 @@ +package com.baeldung.algorithms.perfectnumber; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PerfectNumberUnitTest { + @Test + void givenPerfectNumber_whenCheckingIsPerfectBruteForce_thenReturnTrue() { + assertTrue(PerfectNumber.isPerfectBruteForce(6)); + } + + @Test + void givenNonPerfectNumber_whenCheckingIsPerfectBruteForce_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectBruteForce(10)); + } + + @Test + void givenNegativeNumber_whenCheckingIsPerfectBruteForce_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectBruteForce(-28)); + } + + @Test + void givenPerfectNumber_whenCheckingIsPerfectStream_thenReturnTrue() { + assertTrue(PerfectNumber.isPerfectStream(28)); + } + + @Test + void givenNonPerfectNumber_whenCheckingIsPerfectStream_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectStream(10)); + } + + @Test + void givenNegativeNumber_whenCheckingIsPerfectStream_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectStream(-6)); + } + + @Test + void givenPerfectNumber_whenCheckingIsPerfectEuclidEuler_thenReturnTrue() { + assertTrue(PerfectNumber.isPerfectEuclidEuler(28)); + } + + @Test + void givenNonPerfectNumber_whenCheckingIsPerfectEuclidEuler_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectEuclidEuler(10)); + } + + @Test + void givenNegativeNumber_whenCheckingIsPerfectEuclidEuler_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectEuclidEuler(-6)); + } + + @Test + void givenPerfectNumber_whenCheckingIsPerfectEuclidEulerUsingShift_thenReturnTrue() { + assertTrue(PerfectNumber.isPerfectEuclidEulerUsingShift(28)); + } + + @Test + void givenNonPerfectNumber_whenCheckingIsPerfectEuclidEulerUsingShift_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectEuclidEulerUsingShift(10)); + } + + @Test + void givenNegativeNumber_whenCheckingIsPerfectEuclidEulerUsingShift_thenReturnFalse() { + assertFalse(PerfectNumber.isPerfectEuclidEulerUsingShift(-6)); + } +} \ No newline at end of file