HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavaMinor

How can I make this primality test algorithm faster?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thiscanprimalitymakealgorithmfastertesthow

Problem

Is it possible to make this algorithm faster ? Algorithm represents primality test for Wagstaff numbers .

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.