简体   繁体   中英

use nextprobableprime() of java to get previousprobableprime

I want to use nextProbablePrime() method of BigInteger to get the prime that is lower than the given number instead of higher.

Is it possible to get it using just one nextProbablePrime call?

I don't know whether it's possible using the nextProbablePrime method (in one call). However, I just had a need for a previousProbablePrime method, and I came up with the following method that uses the isProbablePrime method in the BigInteger API:

public static BigInteger previousProbablePrime(BigInteger val) {
    // To achieve the same degree of certainty as the nextProbablePrime 
    // method, use x = 100 --> 2^(-100) == (0.5)^100.
    int certainty = 100;
    do {
        val = val.subtract(BigInteger.ONE);
    } while (!val.isProbablePrime(certainty));
    return val;
}

I set up the following test just to compare the speed (and accuracy) to the nextProbablePrime method:

private static void testPreviousProbablePrime() {
    BigInteger min = BigInteger.ONE; // exclusive
    BigInteger max = BigInteger.valueOf(1000000); // exclusive
    BigInteger val;

    // Create a list of prime numbers in the range given by min and max 
    // using previousProbablePrime method.
    ArrayList<BigInteger> listPrev = new ArrayList<BigInteger>();
    Stopwatch sw = new Stopwatch();
    sw.start();

    val = BigIntegerUtils.previousProbablePrime(max);
    while (val.compareTo(min) > 0) {
        listPrev.add(val);
        val = BigIntegerUtils.previousProbablePrime(val);
    }
    sw.stop();
    System.out.println("listPrev = " + listPrev.toString());
    System.out.println("number of items in list = " + listPrev.size());
    System.out.println("previousProbablePrime time = " + sw.getHrMinSecMsElapsed());

    System.out.println();

    // Create a list of prime numbers in the range given by min and max 
    // using nextProbablePrime method.
    ArrayList<BigInteger> listNext = new ArrayList<BigInteger>();
    sw.reset();
    sw.start();

    val = min.nextProbablePrime();
    while (val.compareTo(max) < 0) {
        listNext.add(val);
        val = val.nextProbablePrime();
    }
    sw.stop();
    System.out.println("listNext = " + listNext.toString());
    System.out.println("number of items in list = " + listNext.size());
    System.out.println("nextProbablePrime time = " + sw.getHrMinSecMsElapsed());

    System.out.println();

    // Compare the two lists.
    boolean identical = true;
    int lastIndex = listPrev.size() - 1;
    for (int i = 0; i <= lastIndex; i++) {
        int j = lastIndex - i;
        if (listPrev.get(j).compareTo(listNext.get(i)) != 0) {
            identical = false;
            break;
        }
    }
    System.out.println("Lists are identical?  " + identical);
}

The Stopwatch class is just a basic custom class to track the execution time, so modify those parts to suit the class you might have for this.

I tested for the ranges from 1 to 10000, 100000, and 1000000. The previousProbablePrime method took longer to execute in all three tests. However, it appeared that the difference in execution time increased only modestly with each 10x increase in range size. For 10000, previousProbablePrime executed in just under a second, while nextProbablePrime came in at around 200 ms, for a difference of about 700 or 800 ms. For 1000000, the difference was only about 2 seconds, even though the execution times were 9 and 7 seconds, respectively. Conclusion, the difference in execution time increases slower than the range size.

In all tests, the two lists contained the identical set of prime numbers.

This level of efficiency was sufficient for my needs...might work for you too.

EDIT
Modified method implementation to be more efficient and potentially faster, though I have not tested.

public static BigInteger previousProbablePrime(BigInteger val) {
    if (val.compareTo(BigInteger.TWO) < 0) {
        throw new IllegalArgumentException("Value must be greater than 1.");
    }

    // Handle single unique case where even prime is returned.
    if (val.equals(new BigInteger("3"))) {
        return BigInteger.TWO;
    }

    // To achieve the same degree of certainty as the nextProbablePrime 
    // method, use x = 100 --> 2^(-100) == (0.5)^100.
    int certainty = 100;

    boolean isEven = val.mod(BigInteger.TWO).equals(BigInteger.ZERO);

    val = isEven ? val.subtract(BigInteger.ONE) : val.subtract(BigInteger.TWO);

    while (!val.isProbablePrime(certainty)) {
        // At this point, only check odd numbers.
        val = val.subtract(BigInteger.TWO);
    }

    return val;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM