Program to find all primes in a very large given range of integers

限于喜欢 提交于 2019-12-01 06:10:37

You are given

1 <= m <= n <= 1000000000, n-m<=100000

these are very small numbers. To sieve a range with an upper bound of n, you need the primes to √n. Here you know n <= 10^9, so √n < 31623, so you need at worst the primes to 31621. There are 3401. You can generate them with a standard sieve in a few microseconds.

Then you can simply sieve the small range from m to n by marking the multiples of the primes you've sieved before, stopping when the prime exceeds √n. Some speedup can be gained by eliminating the multiples of some small primes from the sieve, but the logic becomes more complicated (you need to treat sieves with small m specially).

public int[] chunk(int m, int n) {
    if (n < 2) return null;
    if (m < 2) m = 2;
    if (n < m) throw new IllegalArgumentException("Borked");
    int root = (int)Math.sqrt((double)n);
    boolean[] sieve = new boolean[n-m+1];
    // primes is the global array of primes to 31621 populated earlier
    // primeCount is the number of primes stored in primes, i.e. 3401
    // We ignore even numbers, but keep them in the sieve to avoid index arithmetic.
    // It would be very simple to omit them, though.
    for(int i = 1, p = primes[1]; i < primeCount; ++i) {
        if ((p = primes[i]) > root) break;
        int mult;
        if (p*p < m) {
            mult = (m-1)/p+1;
            if (mult % 2 == 0) ++mult;
            mult = p*mult;
        } else {
            mult = p*p;
        }
        for(; mult <= n; mult += 2*p) {
            sieve[mult-m] = true;
        }
    }
    int count = m == 2 ? 1 : 0;
    for(int i = 1 - m%2; i < n-m; i += 2) {
        if (!sieve[i]) ++count;
    }
    int sievedPrimes[] = new int[count];
    int pi = 0;
    if (m == 2) {
        sievedPrimes[0] = 2;
        pi = 1;
    }
    for(int i = 1 - m%2; i < n-m; i += 2) {
        if (!sieve[i]) {
            sievedPrimes[pi++] = m+i;
        }
    }
    return sievedPrimes;
}

Using a BitSet or any other type of packed flag-array would reduce the memory usage and thus may give a significant speed-up due to better cache-locality.

Use a BitSet instead of an Array of Boolean.

public static BitSet primes (final int MAX)
{
     BitSet primes = new BitSet (MAX);
     // make only odd numbers candidates...
     for (int i = 3; i < MAX; i+=2)
     {
        primes.set(i);
     }
     // ... except no. 2
     primes.set (2, true);
     for (int i = 3; i < MAX; i+=2)
     {
        /*
            If a number z is already  eliminated (like 9),
             because it is itself a multiple of a prime 
            (example: 3), then all multiples of z (9) are
            already eliminated.
        */
        if (primes.get (i))
        {
            int j = 3 * i;
            while (j < MAX)
            {
                if (primes.get (j))
                    primes.set (j, false);
                j += (2 * i);
            }
        }
    }
    return primes;
}   

do you HAVE to store the result in the array? how about a method that computes if a given integer is a prime or not and just call it for each number in {left,left+1,...,right} ?

You can always use an offset when accessing the isNotPrime array.

Given m, n:

boolean[] isNotPrime = new boolean[n-m+1];

// to now if number x is primer or not
boolean xIsPrime = isNotPrime[x-m];

Here m is the offset.

You are not forced to have one large array : you can keep a list of the primes found so far, and test using multiple arrays, having values = array_slot + offset(already tested values). Once you have finished the values from i to j, you add j-i to offset and start a new array starting from J.

You can remove even numbers from your array, that would save you some space (values = array_slot * 2 - 1).

Since the distance between m and n is relatively small, you can brute-force and use a fast primality test algorithm in every number between m and n.

If you allow probabilistic algorithms, you can use Miller-Rabin test. Let M = n-m <= 10^5 and N = n <= 10^9. The complexity of the brute-force algorithm would be O(k M (log N)^3), where k is a constant that controls probabilistic guarantees (for practical applications, k can be set to 10).

For the limits of the problem, this complexity will be around 10^9.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!