Skip to content

Commit 7eba2cd

Browse files
committed
add another interesting prime test candidate +++ renamed variable
1 parent ca5fe6a commit 7eba2cd

7 files changed

Lines changed: 102 additions & 32 deletions

File tree

src/main/java/de/tilman_neumann/jml/factor/tdiv/LemireIntTrialDivision.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,16 @@ public int findSingleFactor(int N) {
6868
if ((N & 1) == 0) return 2;
6969

7070
for (int i = 1; i < primes.length; i++) {
71-
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
72-
// the return branch is unlikely -> always the same data processing; preloading the arrays
7371
if (factorFound (N, i)) return primes[i];
7472
}
7573

7674
return -1;
7775
}
7876

7977
private boolean factorFound(int N, int i) {
78+
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
79+
// the return branch is unlikely -> always the same data processing; preloading the arrays
80+
8081
// 1. get pre-computed inverse and limit
8182
int inv = modularInverses[i];
8283
int limit = limits[i];

src/main/java/de/tilman_neumann/jml/factor/tdiv/LemireTrialDivision.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,16 @@ public int findSingleFactor(long N) {
6969
if ((N & 1) == 0) return 2;
7070

7171
for (int i = 1; i < primes.length; i++) {
72-
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
73-
// the return branch is unlikely -> always the same data processing; preloading the arrays
7472
if (factorFound (N, i)) return primes[i];
7573
}
7674

7775
return -1;
7876
}
7977

8078
private boolean factorFound(long N, int i) {
79+
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
80+
// the return branch is unlikely -> always the same data processing; preloading the arrays
81+
8182
// 1. get pre-computed inverse and limit
8283
long inv = modularInverses[i];
8384
long limit = limits[i];

src/main/java/de/tilman_neumann/jml/primes/exact/AutoExpandingPrimesArray.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ public class AutoExpandingPrimesArray implements SieveCallback {
3939
private BinarySearch bs = new BinarySearch();
4040

4141
// lazy-initialized singleton
42-
private static AutoExpandingPrimesArray the_instance = null;
42+
private static AutoExpandingPrimesArray theInstance = null;
4343

4444
/**
4545
* @return the only TDivPrimeTest instance (singleton)
4646
*/
4747
public static synchronized final AutoExpandingPrimesArray get() {
48-
if (the_instance == null) {
49-
the_instance = new AutoExpandingPrimesArray();
48+
if (theInstance == null) {
49+
theInstance = new AutoExpandingPrimesArray();
5050
}
51-
return the_instance;
51+
return theInstance;
5252
}
5353

5454
/**

src/main/java/de/tilman_neumann/jml/primes/exact/BarrettPrimeTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ public class BarrettPrimeTest {
3939
private long[] pinv;
4040

4141
/** lazy-initialized singleton */
42-
private static BarrettPrimeTest the_instance = null;
42+
private static BarrettPrimeTest theInstance = null;
4343

4444
/**
4545
* @return the only TDivPrimeTest instance (singleton)
4646
*/
4747
public static synchronized final BarrettPrimeTest getInstance() {
48-
if (the_instance == null) {
49-
the_instance = new BarrettPrimeTest();
48+
if (theInstance == null) {
49+
theInstance = new BarrettPrimeTest();
5050
}
51-
return the_instance;
51+
return theInstance;
5252
}
5353

5454
private BarrettPrimeTest() {

src/main/java/de/tilman_neumann/jml/primes/exact/LemireIntPrimeTest.java

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.apache.logging.log4j.LogManager;
1818

1919
import de.tilman_neumann.jml.BinarySearch;
20+
import de.tilman_neumann.jml.primes.util.PrimeRestsMod30030;
2021

2122
/**
2223
* A deterministic prime test for N < 32 bit using Lemire division.
@@ -35,26 +36,27 @@ public class LemireIntPrimeTest {
3536
private static final int MAX_PRIME_FACTOR = 1<<16; // sufficient for numbers to factor with 32 bits
3637

3738
private static final BinarySearch binarySeach = new BinarySearch();
38-
39+
private PrimeRestsMod30030 primeRestsMod30030 = PrimeRestsMod30030.getInstance();
40+
3941
private static int MAX_INDEX; // for N<32 bit this would be 4792
4042

4143
private static int[] primes;
4244
private static int[] modularInverses;
4345
private static int[] limits;
44-
46+
4547
// lazy-initialized singleton
46-
private static LemireIntPrimeTest the_instance = null;
48+
private static LemireIntPrimeTest theInstance = null;
4749

4850
/**
4951
* @return the only TDivPrimeTest instance (singleton)
5052
*/
5153
public static synchronized final LemireIntPrimeTest getInstance() {
52-
if (the_instance == null) {
53-
the_instance = new LemireIntPrimeTest();
54+
if (theInstance == null) {
55+
theInstance = new LemireIntPrimeTest();
5456
}
55-
return the_instance;
57+
return theInstance;
5658
}
57-
59+
5860
private LemireIntPrimeTest() {
5961
primes = SmallPrimes.generatePrimes(MAX_PRIME_FACTOR);
6062
MAX_INDEX = primes.length - 1;
@@ -85,8 +87,6 @@ boolean isPrime_v1(int N) {
8587
int pmax = (int) Math.sqrt(N);
8688

8789
for (int i = 1; primes[i]<=pmax; i++) {
88-
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
89-
// the return branch is unlikely -> always the same data processing; preloading the arrays
9090
if (factorFound (N, i)) return false;
9191
}
9292

@@ -102,14 +102,38 @@ boolean isPrime_v2(int N) {
102102
int imax = binarySeach.getInsertPosition(primes, MAX_INDEX, pmax);
103103

104104
for (int i = 1; i<=imax; i++) {
105-
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
106-
// the return branch is unlikely -> always the same data processing; preloading the arrays
107105
if (factorFound (N, i)) return false;
108106
}
109107

110108
return true;
111109
}
112110

111+
// not public because isPrimeUnrolled() is faster; unrolling this approach did not give a faster variant yet
112+
boolean isPrime_v3(int N) {
113+
if (N==1) return false;
114+
if ((N&1)==0) return N==2;
115+
116+
int pmax = (int) Math.sqrt(N);
117+
int imax = binarySeach.getInsertPosition(primes, MAX_INDEX, pmax);
118+
int imax1 = Math.min(imax, 3247);
119+
120+
int i = 1;
121+
for ( ; i<=imax1; i++) {
122+
if (factorFound (N, i)) return false;
123+
}
124+
125+
if (i < imax) {
126+
// Test residues % 30030. Note that N<30030 have been exclude by trial division above.
127+
if (!primeRestsMod30030.isPossiblyPrime(N)) return false;
128+
129+
for ( ; i<=imax; i++) {
130+
if (factorFound (N, i)) return false;
131+
}
132+
}
133+
134+
return true;
135+
}
136+
113137
public boolean isPrime/*Unrolled*/(int N) {
114138
if (N==1) return false;
115139
if ((N&1)==0) return N==2;
@@ -137,6 +161,9 @@ boolean isPrime_v2(int N) {
137161
}
138162

139163
private boolean factorFound(int N, int i) {
164+
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
165+
// the return branch is unlikely -> always the same data processing; preloading the arrays
166+
140167
// 1. get pre-computed inverse and limit
141168
int inv = modularInverses[i];
142169
int limit = limits[i];

src/main/java/de/tilman_neumann/jml/primes/exact/LemirePrimeTest.java

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.apache.logging.log4j.LogManager;
1818

1919
import de.tilman_neumann.jml.BinarySearch;
20+
import de.tilman_neumann.jml.primes.util.PrimeRestsMod30030;
2021

2122
/**
2223
* A deterministic prime test for N < 32 bit (or even a few bits more) using Lemire division.
@@ -34,24 +35,25 @@ public class LemirePrimeTest {
3435
private static final int MAX_PRIME_FACTOR = 1 << ((MAX_N_BITS+1)/2);
3536

3637
private static final BinarySearch binarySeach = new BinarySearch();
37-
38+
private PrimeRestsMod30030 primeRestsMod30030 = PrimeRestsMod30030.getInstance();
39+
3840
private static int MAX_INDEX; // for N<32 bit this would be 4792
3941

4042
private int[] primes;
4143
private long[] modularInverses;
4244
private long[] limits;
4345

4446
// lazy-initialized singleton
45-
private static LemirePrimeTest the_instance = null;
47+
private static LemirePrimeTest theInstance = null;
4648

4749
/**
4850
* @return the only TDivPrimeTest instance (singleton)
4951
*/
5052
public static synchronized final LemirePrimeTest getInstance() {
51-
if (the_instance == null) {
52-
the_instance = new LemirePrimeTest();
53+
if (theInstance == null) {
54+
theInstance = new LemirePrimeTest();
5355
}
54-
return the_instance;
56+
return theInstance;
5557
}
5658

5759
private LemirePrimeTest() {
@@ -84,8 +86,6 @@ boolean isPrime_v1(int N) {
8486
int pmax = (int) Math.sqrt(N);
8587

8688
for (int i = 1; primes[i]<=pmax; i++) {
87-
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
88-
// the return branch is unlikely -> always the same data processing; preloading the arrays
8989
if (factorFound (N, i)) return false;
9090
}
9191

@@ -101,14 +101,38 @@ boolean isPrime_v2(int N) {
101101
int imax = binarySeach.getInsertPosition(primes, MAX_INDEX, pmax);
102102

103103
for (int i = 1; i<=imax; i++) {
104-
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
105-
// the return branch is unlikely -> always the same data processing; preloading the arrays
106104
if (factorFound (N, i)) return false;
107105
}
108106

109107
return true;
110108
}
111109

110+
// not public because isPrimeUnrolled() is faster; unrolling this approach did not give a faster variant yet
111+
boolean isPrime_v3(int N) {
112+
if (N==1) return false;
113+
if ((N&1)==0) return N==2;
114+
115+
int pmax = (int) Math.sqrt(N);
116+
int imax = binarySeach.getInsertPosition(primes, MAX_INDEX, pmax);
117+
int imax1 = Math.min(imax, 3247);
118+
119+
int i = 1;
120+
for ( ; i<=imax1; i++) {
121+
if (factorFound (N, i)) return false;
122+
}
123+
124+
if (i < imax) {
125+
// Test residues % 30030. Note that N<30030 have been exclude by trial division above.
126+
if (!primeRestsMod30030.isPossiblyPrime(N)) return false;
127+
128+
for ( ; i<=imax; i++) {
129+
if (factorFound (N, i)) return false;
130+
}
131+
}
132+
133+
return true;
134+
}
135+
112136
public boolean isPrime/*Unrolled*/(int N) {
113137
if (N==1) return false;
114138
if ((N&1)==0) return N==2;
@@ -136,6 +160,9 @@ boolean isPrime_v2(int N) {
136160
}
137161

138162
private boolean factorFound(long N, int i) {
163+
// for hard numbers like big semiprimes finding a factor (early) is unlikely and JIT predicts that
164+
// the return branch is unlikely -> always the same data processing; preloading the arrays
165+
139166
// 1. get pre-computed inverse and limit
140167
long inv = modularInverses[i];
141168
long limit = limits[i];

src/test/java/de/tilman_neumann/jml/primes/exact/TDivPrimeTestPerformanceTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ private static void test() {
9393
t1 = System.nanoTime();
9494
LOG.info("LEMIRE_TEST.isPrime_v2 took " + (t1-t0) + " ns");
9595

96+
t0 = System.nanoTime();
97+
for (int n : TEST_NUMBERS) {
98+
LEMIRE_TEST.isPrime_v3(n);
99+
}
100+
t1 = System.nanoTime();
101+
LOG.info("LEMIRE_TEST.isPrime_v3 took " + (t1-t0) + " ns");
102+
96103
t0 = System.nanoTime();
97104
for (int n : TEST_NUMBERS) {
98105
LEMIRE_TEST.isPrime/*Unrolled*/(n);
@@ -114,6 +121,13 @@ private static void test() {
114121
t1 = System.nanoTime();
115122
LOG.info("LEMIRE_INT_TEST.isPrime_v2 took " + (t1-t0) + " ns");
116123

124+
t0 = System.nanoTime();
125+
for (int n : TEST_NUMBERS) {
126+
LEMIRE_INT_TEST.isPrime_v3(n);
127+
}
128+
t1 = System.nanoTime();
129+
LOG.info("LEMIRE_INT_TEST.isPrime_v3 took " + (t1-t0) + " ns");
130+
117131
t0 = System.nanoTime();
118132
for (int n : TEST_NUMBERS) {
119133
LEMIRE_INT_TEST.isPrime/*Unrolled*/(n);

0 commit comments

Comments
 (0)