View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.numbers.primes;
18  
19  import java.util.HashSet;
20  import java.util.List;
21  
22  import org.junit.jupiter.api.Assertions;
23  import org.junit.jupiter.api.Test;
24  
25  class PrimesTest {
26  
27      static final int[] PRIMES = {
28          //primes here have been verified one by one using Dario Alejandro Alpern's tool.
29          //see http://www.alpertron.com.ar/ECM.HTM
30          2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 43, 47, 53, 71, 73, 79, 89, 97,
31          107, 137, 151, 157, 271, 293, 331, 409, 607, 617, 683, 829,
32          1049, 1103, 1229, 1657,
33          2039, 2053, //around first boundary in miller-rabin
34          2251, 2389, 2473, 2699, 3271, 3389, 3449, 5653, 6449, 6869, 9067, 9091,
35          11251, 12433, 12959, 22961, 41047, 46337, 65413, 80803, 91577, 92693,
36          118423, 656519, 795659,
37          1373639, 1373677, //around second boundary in miller-rabin
38          588977, 952381,
39          1013041, 1205999, 2814001,
40          22605091,
41          25325981, 25326023, //around third boundary in miller-rabin
42          100000007, 715827881,
43          2147483647, //Integer.MAX_VALUE
44          // Prime factors added for Miller-Rabin edge case using Matlab 2023, factor(n)
45          3761, 4513, // factor(16973393)
46          3943, 6571, // factor(25909453)
47          };
48  
49      static final int[] NOT_PRIMES = {
50          //composite chosen at random + particular values used in algorithms such as boundaries for millerRabin
51          4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25,
52          275,
53          2037, 2041, 2045, 2046, 2047, 2048, 2049, 2051, 2055, //around first boundary in miller-rabin
54          9095,
55          463465,
56          1373637, 1373641, 1373651, 1373652, 1373653, 1373654, 1373655, 1373673, 1373675, 1373679, //around second boundary in miller-rabin
57          25325979, 25325983, 25325993, 25325997, 25325999, 25326001, 25326003, 25326007, 25326009, 25326011, 25326021, 25326025, //around third boundary in miller-rabin
58          100000005,
59          1073741341, 1073741823, 2147473649, 2147483641, 2147483643, 2147483645, 2147483646,
60          // Hit branch case in Miller-Rabin when square % n == 1
61          16973393, 25909453
62      };
63  
64      static final int[] BELOW_2 = {Integer.MIN_VALUE, -1, 0, 1};
65  
66      static final HashSet<Integer> PRIMES_SET = new HashSet<>();
67      static {
68          for (int p : PRIMES) {
69              PRIMES_SET.add(p);
70          }
71      }
72  
73      void assertPrimeFactorsException(int n, String expected) {
74          try {
75              Primes.primeFactors(n);
76              Assertions.fail("Exception not thrown");
77          } catch (IllegalArgumentException e) {
78              Assertions.assertEquals(expected, e.getMessage());
79          }
80      }
81  
82      void assertNextPrimeException(int n, String expected) {
83          try {
84              Primes.nextPrime(n);
85              Assertions.fail("Exception not thrown");
86          } catch (IllegalArgumentException e) {
87              Assertions.assertEquals(expected, e.getMessage());
88          }
89      }
90  
91      @Test
92      void testNextPrime() {
93  
94          Assertions.assertEquals(2, Primes.nextPrime(0));
95          Assertions.assertEquals(2, Primes.nextPrime(1));
96          Assertions.assertEquals(2, Primes.nextPrime(2));
97          Assertions.assertEquals(3, Primes.nextPrime(3));
98          Assertions.assertEquals(5, Primes.nextPrime(4));
99          Assertions.assertEquals(5, Primes.nextPrime(5));
100 
101         for (int i = 0; i < SmallPrimes.PRIMES.length - 1; i++) {
102             for (int j = SmallPrimes.PRIMES[i] + 1; j <= SmallPrimes.PRIMES[i + 1]; j++) {
103                 Assertions.assertEquals(SmallPrimes.PRIMES[i + 1], Primes.nextPrime(j));
104             }
105         }
106 
107         Assertions.assertEquals(25325981, Primes.nextPrime(25325981));
108         for (int i = 25325981 + 1; i <= 25326023; i++) {
109             Assertions.assertEquals(25326023, Primes.nextPrime(i));
110         }
111 
112         Assertions.assertEquals(Integer.MAX_VALUE, Primes.nextPrime(Integer.MAX_VALUE - 10));
113         Assertions.assertEquals(Integer.MAX_VALUE, Primes.nextPrime(Integer.MAX_VALUE - 1));
114         Assertions.assertEquals(Integer.MAX_VALUE, Primes.nextPrime(Integer.MAX_VALUE));
115 
116         assertNextPrimeException(Integer.MIN_VALUE, String.format(Primes.NUMBER_TOO_SMALL, Integer.MIN_VALUE, 0));
117         assertNextPrimeException(-1, String.format(Primes.NUMBER_TOO_SMALL, -1, 0));
118         assertNextPrimeException(-13, String.format(Primes.NUMBER_TOO_SMALL, -13, 0));
119     }
120 
121     @Test
122     void testIsPrime() {
123         for (int i : BELOW_2) {
124             Assertions.assertFalse(Primes.isPrime(i));
125         }
126         for (int i : NOT_PRIMES) {
127             Assertions.assertFalse(Primes.isPrime(i));
128         }
129         for (int i : PRIMES) {
130             Assertions.assertTrue(Primes.isPrime(i));
131         }
132     }
133 
134     static int sum(List<Integer> numbers) {
135         int out = 0;
136         for (int i:numbers) {
137             out += i;
138         }
139         return out;
140     }
141 
142     static int product(List<Integer> numbers) {
143         int out = 1;
144         for (int i : numbers) {
145             out *= i;
146         }
147         return out;
148     }
149 
150     static void checkPrimeFactors(List<Integer> factors) {
151         for (int p : factors) {
152             if (!PRIMES_SET.contains(p)) {
153                 Assertions.fail("Not found in primes list: " + p);
154             }
155         }
156     }
157 
158     @Test
159     void testPrimeFactors() {
160         for (int i : BELOW_2) {
161             assertPrimeFactorsException(i, String.format(Primes.NUMBER_TOO_SMALL, i, 2));
162         }
163         for (int i : NOT_PRIMES) {
164             List<Integer> factors = Primes.primeFactors(i);
165             checkPrimeFactors(factors);
166             int prod = product(factors);
167             Assertions.assertEquals(i, prod);
168         }
169         for (int i : PRIMES) {
170             List<Integer> factors = Primes.primeFactors(i);
171             Assertions.assertEquals(i, (int)factors.get(0));
172             Assertions.assertEquals(1, factors.size());
173         }
174     }
175 }