简体   繁体   English

如何有效地实现Eratosphenes方法来生成质数?

[英]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) 一个字节数组,每个位代表对应的数字是否为prime(0)(不是)(1)
  • A recursion of Filtering.filter() 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? 在2014年12月3日编辑:该段代码如何处理?

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 . 而是编写使用低级位操作运算符(例如~&| )来实现getset

If you're not up to that, then consider using BitSet , a JDK-provided class which serves the same purpose. 如果您BitSet ,请考虑使用BitSet ,这是JDK提供的类,具有相同的作用。

If you want to learn how it's done, then simply open BitSet 's source code. 如果您想了解它是如何完成的,只需打开BitSet的源代码即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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