简体   繁体   中英

How to efficiently implement Eratosphenes method to generate prime numbers?

I use the following components in my code:

  • A byte array, each bit representing whether the correspondent number is prime(0) or not(1)
  • A recursion of Filtering.filter()

I want to ascertain whether these parts make it more efficient or actually slow it down. Any other advices also appreciated.

Code:

import java.lang.Math;
import java.util.*;

class Container{
    public final byte[] binary_array;
    private final int bit_length;

    public Container(int nominal_bit_length){
            int byte_length = (int)Math.ceil(nominal_bit_length / 8.0);
            this.binary_array = new byte[byte_length];
            this.bit_length = 8 * byte_length;
    }

    private String toBinaryString(int index){//convert into a binary string the byte value on which the bit number refered by the index exists
            int byte_index = index / 8;
            //System.out.println(index);
            String str = Integer.toBinaryString(this.binary_array[byte_index]);
            String formatted = ("00000000" + str).substring(str.length());
            return formatted;
    }

    public char get(int index){
            String str = this.toBinaryString(index);
            return str.charAt(index % 8);//
    }

    public char set(int index, char value){
            StringBuilder str = new StringBuilder(this.toBinaryString(index));
            char temp = str.charAt(index % 8);//
            str.setCharAt(index % 8, value);//
            int byte_index = index / 8;
            this.binary_array[byte_index] = (byte)Integer.parseUnsignedInt(str.toString(), 2);
            return temp;
    }

    public int length(){
            return this.bit_length;
    }

    public static Container preset(){
            Container c = new Container(8);
            c.set(1-1, '1');
            c.set(4-1, '1');
            c.set(6-1, '1');
            c.set(8-1, '1');
            return c;
    }



}

class Screener{



    private static void filterMultiplesOf(int num, Container container){
            if (num == 1){
             return;
            }
            int i = 2;
            while ((i * num - 1) < container.length()){
                    container.set(i * num - 1, '1');
                    i++;
            }
    }

    public static void filter(Container c){
            int num = c.length();
            if (num <= 8){
                    c = Container.preset();
            } else{
                    Container base = new Container((int)Math.floor(Math.sqrt(num)));
                    filter(base);
                    for (int i = 0; i < base.length(); i++){
                            if (base.get(i) == '0'){
                                    filterMultiplesOf(i+1, c);
                            }
                    }
            }

    }
}

public class Prime2{
    public static void main(String[] args){
            Scanner reader = new Scanner(System.in);
            int num = reader.nextInt();
            Container c = new Container(num);
            Screener.filter(c);


            for (int i = 1; i < c.length(); i++){
                    if (c.get(i) == '0'){
                            System.out.print((i + 1) + " ");
                    } 
            }   
    }

}

Edit at 12-03-2014: What about this segment code?

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;


public class PrimeGenerator {



    public static Set<Integer> prime(int num){
            if (num <= 2){
                    Set<Integer> foo = new HashSet<>();
                    foo.add(2);
                    return foo;
            }
            IntStream stream = IntStream.rangeClosed(1, num);
            Set<Integer> base = prime((int)Math.ceil(Math.sqrt(num)));
            IntStream multiples = base.stream().flatMapToInt((factor) -> (IntStream.rangeClosed(2, (int)Math.floorDiv(num, factor)).map(n -> n * factor)));
            Set<Integer> primeset = stream.collect(HashSet::new, HashSet::add, HashSet::addAll);
            Set<Integer> nonprimeset = multiples.collect(HashSet::new, HashSet::add, HashSet::addAll);
            primeset.removeAll(nonprimeset);
            primeset.remove(1);
            return primeset;
    }

    public static void main(String[] args) {
            // TODO code application logic here
            prime(100000).stream().map(num -> num + "  ").forEach(System.out::print);
    }

}

as well as this:

import java.lang.Math;
import java.util.*;

/**
* Variation of BitSet which does NOT interpret the highest bit synonymous with
* its length.
*
* @author casper.bang@gmail.com
*/
class FixedBitSet extends BitSet{

    int fixedLength;

    public FixedBitSet(int fixedLength){
        super(fixedLength);
        this.fixedLength = fixedLength;
}

    @Override
    public int length() {
        return fixedLength;
    }
}


class Screener{

    private static FixedBitSet preset;

    static{
            preset = new FixedBitSet(4);
            preset.set(1-1, true);
            preset.set(4-1, true);
    }

    private static void filterMultiplesOf(int num, FixedBitSet bitset){
            //System.out.println("--------");

            if (num == 1){
                    return;
            }

            int i = 2;
            while ((i * num - 1) < bitset.length()){
                    bitset.set(i * num - 1, true);
                    i++;
            }
    }

    public static void filter(FixedBitSet bitset){
            //System.out.println("--------");

            int num = bitset.length();
            if (num <= 4){
                    //System.out.println("--------");
                    bitset = preset;
            } else{
                    FixedBitSet base = new FixedBitSet((int)Math.floor(Math.sqrt(num)));
                    filter(base);
                    for (int i = 0; i < base.length(); i++){
                            if(!base.get(i)){
                                    filterMultiplesOf(i + 1, bitset);
                            }
                    }
            }

    }
}

public class Prime3{

    public static void main(String[] args){
            Scanner reader = new Scanner(System.in);
            int num = reader.nextInt();
            FixedBitSet bs = new FixedBitSet(num);
//                System.out.println(bs.length());
            Screener.filter(bs);

            for (int i = 1; i < bs.length(); i++){
                    if(!bs.get(i)){
                            System.out.print((i + 1) + " ");
                    }
            }
    }
}

Your "efficient" usage of a byte array is immaterial to the bad performance of your code, which uses string building to implement getting and setting.

Instead write code which uses low-level bit-manipulation operators (such as ~ , & , and | ) to implement get and set .

If you're not up to that, then consider using BitSet , a JDK-provided class which serves the same purpose.

If you want to learn how it's done, then simply open BitSet 's source code.

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