1+ import java .math .BigInteger ;
2+ import java .util .Random ;
3+
4+ public final class EulerPseudoprime {
5+
6+ private EulerPseudoprime () {}
7+
8+ private static final Random RANDOM = new Random ();
9+
10+ public static boolean isProbablePrime (BigInteger n , int trials ) {
11+ if (n .compareTo (BigInteger .TWO ) < 0 ) {
12+ return false ;
13+ }
14+ if (n .equals (BigInteger .TWO ) || n .equals (BigInteger .valueOf (3 ))) {
15+ return true ;
16+ }
17+ if (n .mod (BigInteger .TWO ).equals (BigInteger .ZERO )) {
18+ return false ;
19+ }
20+
21+ for (int i = 0 ; i < trials ; i ++) {
22+ BigInteger a = uniformRandom (BigInteger .TWO , n .subtract (BigInteger .TWO ));
23+ BigInteger jacobi = BigInteger .valueOf (jacobiSymbol (a , n ));
24+
25+ if (jacobi .equals (BigInteger .ZERO )) {
26+ return false ;
27+ }
28+
29+ BigInteger exp = n .subtract (BigInteger .ONE ).divide (BigInteger .TWO );
30+ BigInteger modExp = a .modPow (exp , n );
31+
32+ if (!modExp .equals (jacobi .mod (n ))) {
33+ return false ;
34+ }
35+ }
36+ return true ;
37+ }
38+
39+ public static int jacobiSymbol (BigInteger a , BigInteger n ) {
40+ if (n .signum () <= 0 || n .mod (BigInteger .TWO ).equals (BigInteger .ZERO )) {
41+ throw new IllegalArgumentException ("n must be a positive odd integer." );
42+ }
43+
44+ int result = 1 ;
45+ a = a .mod (n );
46+
47+ while (a .compareTo (BigInteger .ZERO ) != 0 ) {
48+ while (a .mod (BigInteger .TWO ).equals (BigInteger .ZERO )) {
49+ a = a .divide (BigInteger .TWO );
50+ BigInteger nMod8 = n .mod (BigInteger .valueOf (8 ));
51+ if (nMod8 .equals (BigInteger .valueOf (3 )) || nMod8 .equals (BigInteger .valueOf (5 ))) {
52+ result = -result ;
53+ }
54+ }
55+
56+ BigInteger temp = a ;
57+ a = n ;
58+ n = temp ;
59+
60+ if (a .mod (BigInteger .valueOf (4 )).equals (BigInteger .valueOf (3 )) && n .mod (BigInteger .valueOf (4 )).equals (BigInteger .valueOf (3 ))) {
61+ result = -result ;
62+ }
63+ a = a .mod (n );
64+ }
65+ return n .equals (BigInteger .ONE ) ? result : 0 ;
66+ }
67+
68+ private static BigInteger uniformRandom (BigInteger min , BigInteger max ) {
69+ BigInteger result ;
70+ do {
71+ result = new BigInteger (max .bitLength (), RANDOM );
72+ } while (result .compareTo (min ) < 0 || result .compareTo (max ) > 0 );
73+ return result ;
74+ }
75+
76+ public static void main (String [] args ) {
77+ // Define the numbers to test and the number of trials for the test.
78+ int trials = 20 ;
79+ String [] testNumbers = {
80+ "7" , // Small prime
81+ "10" , // Small even composite
82+ "91" , // Small odd composite
83+ "563" , // A known prime number
84+ "1105" , // An Euler pseudoprime to base 2
85+ "294409" , // A larger prime number
86+ "294411" // A larger composite number
87+ };
88+
89+ System .out .printf ("Running Euler Primality Test with %d trials...%n%n" , trials );
90+
91+ for (String numStr : testNumbers ) {
92+ BigInteger n = new BigInteger (numStr );
93+ boolean isPrime = isProbablePrime (n , trials );
94+ String result = isPrime ? "Probably Prime" : "Composite" ;
95+ System .out .printf ("Is %s prime? --> %s%n" , n , result );
96+ }
97+ }
98+ }
0 commit comments