snippetjavaMinor
How can I make this primality test algorithm faster?
Viewed 0 times
thiscanprimalitymakealgorithmfastertesthow
Problem
Is it possible to make this algorithm faster ? Algorithm represents primality test for Wagstaff numbers .
very fast corresponding Mathematica code :
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
public class WPT
{
public static void main(String[] args)
{
int n;
n = Integer.parseInt(args[0]);
BigInteger m;
m = BigInteger.valueOf(n);
BigDecimal a = new BigDecimal("1.5");
BigDecimal b = new BigDecimal("5.5");
BigDecimal c = new BigDecimal("13.5");
BigDecimal d = new BigDecimal("16.5");
BigDecimal s;
BigDecimal r;
if (m.mod(BigInteger.valueOf(4)).equals(BigInteger.ONE))
{
s = a;
r = a;
} else {
if (m.mod(BigInteger.valueOf(6)).equals(BigInteger.ONE))
{
s = b;
r = b;
} else {
if (m.mod(BigInteger.valueOf(12)).equals(BigInteger.valueOf(11)) &&
(m.mod(BigInteger.valueOf(10)).equals(BigInteger.valueOf(1))) ||
m.mod(BigInteger.valueOf(10)).equals(BigInteger.valueOf(9)))
{
s = c;
r = c;
} else {
s = d;
r = d;
}
}
}
BigDecimal W;
W = BigDecimal.valueOf(2).pow(n).add(BigDecimal.ONE).divide(BigDecimal.valueOf(3));
int k = (n-1)/2;
for (int i = 1; i <= k; i ++)
{
s = s.pow(4).multiply(BigDecimal.valueOf(8)).subtract(s.pow(2).multiply(BigDecimal.valueOf(8))).add(BigDecimal.ONE).remainder(W).setScale(1, BigDecimal.ROUND_UP);
}
if (s.equals(r))
{
System.out.println("prime");
} else {
System.out.println("composite");
}
}
}very fast corresponding Mathematica code :
p = 269987;
W = (2^(p) + 1)/3;
If[Mod[p, 4] == 1, a = 3/2, If[Mod[p, 6] == 1, a = 11/2,
If[Mod[p, 10] == 3 || Mod[p, 10] == 7, a = 33/2, a = 27/2]]];
For[i = 1; s = a, i <= (p - 1)/2, i++,
s = Mod[ChebyshevT[4, s], W]];
If[s == a, Print["prime"], Print["composite"]];Solution
Avoid dealing with BigDecimals at all costs - they are slow. I changed the formula to work with "twice the number", so my
s is actually 2*s. Further keep the numbers in the loop small by "modding" the intermediate results, too. Finally I tried to simplify the syntax and the initial conditions for s a little bit.import java.math.BigInteger;
public class WPT {
private final static BigInteger _1 = BigInteger.ONE;
private final static BigInteger _2 = _(2);
private final static BigInteger _4 = _(4);
public static BigInteger _(long n) {
return BigInteger.valueOf(n);
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
BigInteger m = _(n);
BigInteger s =
(m.mod(_(4)).equals(_1)) ? _(3) :
(m.mod(_(6)).equals(_1)) ? _(11) :
(m.mod(_(12)).equals(_(11)) &&
(m.mod(_(10)).equals(_1)) ||
m.mod(_(10)).equals(_(9))) ? _(27) : _(33);
BigInteger r = s;
BigInteger W = _2.pow(n).add(_1).divide(_(3));
int k = (n - 1) / 2;
for (int i = 0; i < k; i++) {
BigInteger s2 = s.modPow(_2, W);
BigInteger s4 = s2.modPow(_2, W);
s = s4.subtract(s2.multiply(_4)).add(_2).mod(W);
}
System.out.println(s.equals(r) ? "prime" : "composite");
}
}Code Snippets
import java.math.BigInteger;
public class WPT {
private final static BigInteger _1 = BigInteger.ONE;
private final static BigInteger _2 = _(2);
private final static BigInteger _4 = _(4);
public static BigInteger _(long n) {
return BigInteger.valueOf(n);
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
BigInteger m = _(n);
BigInteger s =
(m.mod(_(4)).equals(_1)) ? _(3) :
(m.mod(_(6)).equals(_1)) ? _(11) :
(m.mod(_(12)).equals(_(11)) &&
(m.mod(_(10)).equals(_1)) ||
m.mod(_(10)).equals(_(9))) ? _(27) : _(33);
BigInteger r = s;
BigInteger W = _2.pow(n).add(_1).divide(_(3));
int k = (n - 1) / 2;
for (int i = 0; i < k; i++) {
BigInteger s2 = s.modPow(_2, W);
BigInteger s4 = s2.modPow(_2, W);
s = s4.subtract(s2.multiply(_4)).add(_2).mod(W);
}
System.out.println(s.equals(r) ? "prime" : "composite");
}
}Context
StackExchange Code Review Q#10390, answer score: 3
Revisions (0)
No revisions yet.