第六章 數學問題 ----------6.13 素數的篩法(第十萬零二個素數)

Curtis_發表於2019-03-22

素數定理:

       給出從整數中抽到素數的概率。從不大於n的自然數隨機選一個,它是素數的概率大約是1/ln n。也就是說在不大於n的自然數裡,總共的素數為 n/lgn

篩法:

  用篩法求素數的基本思想是(本質上也能算是一種預處理):把從1開始的、某一範圍內的正整數從小到大順序排列, 1不是素數,首先把它篩掉。剩下的數中選擇最小的數是素數,然後去掉它的倍數。依次類推,直到篩子為空時結束。如有:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30。

  1不是素數,去掉。剩下的數中2最小,是素數,去掉2的倍數,餘下的數是:3 5 7 9 11 13 15 17 19 21 23 25 27 29 。剩下的數中3最小,是素數,去掉3的倍數,如此下去直到所有的數都被篩完,求出的素數為:2 3 5 7 11 13 17 19 23 29。

 

題目:第十萬零二個素數

  請問,第100002(十萬零二)個素數是多少?   請注意:“2” 是第一素數,“3” 是第二個素數,依此類推。

  程式碼:

public class 第十萬零二個素數 {

    public static void main(String[] args) {
        long now = System.currentTimeMillis();
        // nlognlogn
        f(100002);
        System.out.println("耗時:" + (System.currentTimeMillis() - now) + "ms");
        
        /*============Java自帶的api==========*/
        now = System.currentTimeMillis();
        BigInteger bigInteger = new BigInteger("1");
        for (int i = 1; i <= 100002; i++) {
            bigInteger = bigInteger.nextProbablePrime();
        }
        System.out.println(bigInteger);
        System.out.println("耗時:" + (System.currentTimeMillis() - now) + "ms");
        
        /*==========樸素解法=========*/
        now = System.currentTimeMillis();
        int count = 0;
        long x = 2;
        while(count<100002){
            if (isPrime(x)) {
                count++;
            }
            x++;
        }
        System.out.println(x-1);
        System.out.println("耗時:" + (System.currentTimeMillis() - now) + "ms");
    }
    public static boolean isPrime(long num){
        for (int i = 2; i*i <= num; i++) {
            if (num%i==0) {
                return false;
            }
        }
        return true;
    }
    /**
     * 
     * @param N 第N個素
     */
    private static void f(int N){
        int n = 2;
        // 自然數n之內的素數個數n/ln(n)
        // 得到整數範圍
        while(n/Math.log(n)<N){
            n++;
        }
        int []arr = new int[n];
        int x = 2;
        while(x<n){
            if (arr[x]!=0) {
                x++;
                continue;
            }
            int k=2;
             //對每個x,我們從2倍開始,對x的k倍,全部標記為-1
            while(x*k<n){
                arr[x*k] = -1;
                k++;
            }
            x++;
        }
        // System.out.println(arr);
        // 篩完之後,這個很長的陣列裡面非素數下標對應的值都是-1
        int sum = 0;
        for (int i = 2; i < arr.length; i++) {
            // 是素數,計數+1
            if (arr[i] == 0) {
                // System.out.println(i);
                sum++;
            }
            if (sum == N) {
                System.out.println(i);
                return;
            }
        }
    }

}

  結果:

相關文章