素数を求める vol.2

昨日、素数を求めるプログラムを作ったが 3 億までの素数を求めるのに約 4 時間半かかった。

これが速いのか遅いのかは置いといて、もう少し処理時間の短縮をはかりたい。

最近の PC はマルチコアプロセッサを搭載しているので並列処理させれば処理時間短縮が可能かもしれない。

幸いにも私の PC は 8 コアなので早速試してみました。

ちなみに下記プログラムは、java.util.concurrent パッケージについて調べていた時にあるサイトにあった

サンプルプログラムを参考にさせていただきました。

jp\yucchi\primenumber\PrimeNumber.java
package jp.yucchi.primenumber;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class PrimeNumber implements Callable> {

    private static final long TARGET_NUMBER = 300_000_000L; // 8 の倍数を指定すること(;´Д`)
    private final long from;
    private final long to;

    public PrimeNumber(final long from, final long to) {
        this.from = from;
        this.to = to;
    }

    public static void main(String[] args) {
        long startTime = System.nanoTime();
        long primeCounter = 0L;
        final int procs = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
        ExecutorService executor = Executors.newFixedThreadPool(procs);
        final long range = TARGET_NUMBER / procs;
        List>> futures = new ArrayList<>();
        for (int i = 0; i < procs; i++) {
            final long from = i * range + 1;
            final long to = (i + 1) * range;
            futures.add(executor.submit(new PrimeNumber(from, to)));
        }
        executor.shutdown();
        List totalPrimes = new ArrayList<>();
        for (Future> future : futures) {
            try {
                List primes = future.get();
                totalPrimes.addAll(primes);
            } catch (InterruptedException | ExecutionException ex) {
                Logger.getLogger(PrimeNumber.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        for (Long prime : totalPrimes) {
            primeCounter++;
            System.out.println(prime + " is Prime Number." + " ---> " + primeCounter);
        }
        System.out.println(primeCounter + "個の素数を検出しました。");
        long time = System.nanoTime() - startTime;
        System.out.println((int) (time * 1e-9) / 3_600 + "時間"
                + (int) ((time * 1e-9) / 60) % 60 + "分"
                + (int) (time * 1e-9 % 60) + "秒"
                + Double.toString((time * 1e-9 % 60) % 1).substring(2));
    }

    @Override
    public List call() throws Exception {
        List primes = new ArrayList<>();
        for (long i = from; i < to + 1L; i++) {
            // 2 より大きな偶数は処理をスキップ
            if ((i & 0b1) == 0 && i > 0b10L) {
                continue;
            }
            long j;
            for (j = (long) Math.sqrt(i); i % j != 0; j--) {
                // i を割り切る j を見つけ出す処理
            }
            // i を割り切れず j が 1 の場合素数と判定、ただし i が 1 の場合は除く        
            if (j == 1L && i != 1L) {
                primes.add(i);
            }
        }
        return primes;
    }
}

このプログラムの実行結果は次のようになった。

 

2 is Prime Number. —> 1
3 is Prime Number. —> 2
5 is Prime Number. —> 3
7 is Prime Number. —> 4
11 is Prime Number. —> 5
13 is Prime Number. —> 6
17 is Prime Number. —> 7
19 is Prime Number. —> 8
23 is Prime Number. —> 9
29 is Prime Number. —> 10

    略

299999801 is Prime Number. —> 16252317
299999807 is Prime Number. —> 16252318
299999813 is Prime Number. —> 16252319
299999827 is Prime Number. —> 16252320
299999897 is Prime Number. —> 16252321
299999923 is Prime Number. —> 16252322
299999939 is Prime Number. —> 16252323
299999957 is Prime Number. —> 16252324
299999977 is Prime Number. —> 16252325
16252325個の素数を検出しました。
1時間26分23秒42106727300051716

 

なんと 3 時間も処理時間が短縮できました。(^_^)v

それでも 1 時間半近くかかります。

こんなものなのかなぁ・・・?

素数を求めるアルゴリズムにエラトステネスの篩ってのがあります。

それも試してみましょう。

それでは

おっとそろそろ時間が・・・

続きは Web で!

つづきはまた今度ね♪

Hatena タグ: