1717import org .apache .logging .log4j .LogManager ;
1818
1919import 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 ];
0 commit comments