简体   繁体   中英

Can someone explain me the following prime number generation method?

I guess the method below uses Sieve of Eratosthenes (inclusion-exclusion algorithm) to generate prime numbers up to a given number. What I specifically don't understand, is why it clears bits set on the (j/2) position. Is there a specific rule that is followed? The BitSet contains bits set at position x and this number is either prime number or is composite. So, I am not able to follow what is going on.

public static List<Integer> generatePrimes(int max) {
        BitSet primeSet = new BitSet(max / 2);
        primeSet.set(1, max / 2);
        int limit = (int) Math.sqrt(max);
        for (int i = 3; i <= limit; i += 2) {
            if (!primeSet.get(i / 2)) continue;
            for (int j = i * i; j < max; j += i * 2)
                primeSet.clear(j / 2);

        }

        List<Integer> listOfPrimes = new ArrayList<>();
        listOfPrimes.add(2);
        for (int i = primeSet.nextSetBit(0); i >= 0; i = primeSet.nextSetBit(i + 1)) {
            listOfPrimes.add(i * 2 + 1);
        }
        return listOfPrimes;
    }

It seems that the algorithm is trying to conserve memory by having primeSet represent odd numbers only . Hence the repeated multiplications and divisions by two.

The loop involving primeSet.clear() simply marks every multiple of i as composite.

public static List<Integer> generatePrimes(int max) {

 BitSet primeSet = new BitSet(max / 2);  // host the numbers i up to max/2
 primeSet.set(1, max / 2);               // representing the odds (2i+1)
 int limit = (int) Math.sqrt(max);       //                      below max
 for (int i = 3; i <= limit; i += 2)        // enumerate odds in range 
 {                                          //       3 .. sqrt(max)
     if (!primeSet.get(i / 2)) continue;    // i=2k+1, i/2==(2k+1)/2== k
                                            // (here i is value, k is index)
     for (int j = i * i; j < max; j += i * 2)  // j=i*i is the first multiple
         primeSet.clear(j / 2);        // of i, where the marking off begins
 }                                     //  with step 2*i: 3: 9,6,15,21,...
                                       //                 7: 49,63,77,91,...
 List<Integer> listOfPrimes = new ArrayList<>();
 listOfPrimes.add(2);                     // 2 is known to be prime a priori
 for (int i = primeSet.nextSetBit(0);     // starting with first set bit in
                                          //                 BitSet primeSet,
          i >= 0;                         // 1: until the end of primeSet  
          i = primeSet.nextSetBit(i + 1)  // 3: and go to next set bit
          ) {
     listOfPrimes.add(i * 2 + 1);         // 2: add 2i+1 to the list of primes,
 }                                        // (here i is index)
 return listOfPrimes;
}

As part of the sieve we must mark each third number among odds starting from 9, and in general each n th number, starting from n 2 , as apparently one Rev. Samuel Horsley FRS knew back in 1772 .

It is inefficient to just count along the list – the key to sieve's efficiency is the direct access to memory by address. This address of a number in an array of numbers here is just the number's value itself (this conflation of value and address is also the key to the efficiency of various integer sorting methods).

To directly calculate each 3rd odd number, we must add 6 to the previous one to get the next. For each 5th we add 10, and for each i th – 2*i .


Incidentally this code can be slightly improved. For numbers at the distance 2*i between them, the indices in the set will be at the distance of i . No need to delete by 2 all the time, just calculate the starting index and increment by i .


edit: that code is equivalent to the following pseudocode:

defn primes(max):
  sieve := makeArray(3,5,7 ... max, True)
  for p from 3 to sqrt(max) step 2:
    if sieve[p]:
        for i from p * p to max step 2*p:
            sieve[i] := False
  primes = {2} + {all i in (3,5,7, ... max) such that sieve[i] is True}

除2之外的所有偶数都不是素数,因此不需要迭代它们。

The bits of the primeset represent the numbers 2x+1 where x is the index of the bitset. Thus, when your primeset contains {1, 2, 3, 5, 6, 8, 9, 11, 14} they represent the numbers {3, 5, 7, 11, 13, 17, 19, 23, 29}.

If you're interested in programming with prime numbers I modestly recommend this essay at my blog. Among other things, it explains the Sieve of Eratosthenes and the calculation that is causing you grief.

EDIT: Add simple Sieve of Eratosthenes as explained in comment.

function primes(n)
    sieve := makeArray(2..n, True)
    for p from 2 to n step 1
        if sieve[p]
            output p
            for i from p * p to n step p
                sieve[i] := False

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