Eratosthenes の篩

前回のエントリの続きでまた素数の話.
Team-lablog » 1000万個目の素数を超高速に出力せよ
これに触発されて 1 000 万番目までの素数の出力とその高速化に挑戦してみる.
まずは前回のソースコードをちょっと手直しして,

#include <iostream>
#include <ctime> //実行時間の測定
using namespace std;
#define MAX 180000000

int main(){
	int count = 0;
	clock_t begin, finish;
	begin = clock();
	bool *num;
	num = new bool[MAX];
	for(int i = 0; i < MAX; i++){
		num[i] = true;
	}

	num[0] = false;
	num[1] = false;
	
	for(int i = 2; i * i <= MAX; i++){
		for(int j = i * 2; j <= MAX; j += i){
			if(!num[j]){
				continue;
			}
			num[j] = false;
		}
	}

	for(int i = 0; i < MAX; i++){
		if(num[i]){
			cout << i << " ";
			count++;
			if(count == 10000000){
				cout << endl << "Finished!" << endl;
				break;
			}
		}
	}

	finish = clock();
	cout << (finish - begin) / 1000 << "ms" << endl;

	delete[] num;
	return 0;
}

1 000 万番目の素数は 179 424 673 らしい*1ので最大値は 180 000 000 とした.
プロセッサは Core i5 の 1.3GHz.
で,実行結果.
f:id:kailily:20140809054132p:plain
何も工夫してないのでこんなものか.
偶数を飛ばすように書き換える.

#include <iostream>
#include <ctime>
using namespace std;
#define MAX 180000000

int main(){
	int count = 0;
	clock_t begin, finish;
	begin = clock();
	bool *num;
	num = new bool[MAX];

	for(int i = 2; i < MAX; i += 2){
		num[i] = false;
		num[i + 1] = true;
	}

	num[0] = false;
	num[1] = false;
	num[2] = true;

	for(int i = 3; i * i <= MAX; i += 2){
		for(int j = i * i; j <= MAX; j += i * 2){
			if(!num[j]){
				continue;
			}
			num[j] = false;
		}
	}

	for(int i = 0; i < MAX; i++){
		if(num[i]){
			cout << i << " ";
			count++;
			if(count == 10000000){
				cout << endl << "Finished!" << endl;
				break;
			}
		}
	}

	finish = clock();
	cout << (finish - begin) / 1000 << "ms" << endl;

	delete[] num;
	return 0;
}

実行結果.
f:id:kailily:20140809134642p:plain
かなり速くなった.
まだ無駄な繰り返しがあるので速く出来るとは思うが,思い付かなかったので良さそうな方法を見つけたらまた書く.