エラトステネスの篩
パッケージJava製品開発担当の大です。こんにちは。
震災から11日が経ちました。被害に合われた方々は、現在も大変なご苦労をされていることと思います。
謹んでお見舞い申し上げます。
さて、前回、前々回と素数にまつわる話を書きました。
その際Wikipediaをウロウロしてたらエラトステネスの篩のページにあたったのですが、
アルゴリズムを可視化しているアニメーションGIFが貼ってあって、わかりやすくていいなぁと思ったので、自分でも書いてみたくなりました。で、お手軽にJavaScriptで書いてみました。
可視化の前に
エラトステネスの篩(ふるい)についてものすごくさらっと説明しておくと、ある整数以下の全ての素数を発見するためのアルゴリズムです。
詳しいことはWikipediaのページを見てください。
JavaScriptで可視化
実行ボタンを押してみてください。可視化します。
2~2000までの値を指定して実行できます。
までの素数を検索します。
見つかった素数:
ソース
こんな感じです。久しぶりにJavaScriptを書いてみましたが、やっぱりクロージャのある言語は楽しいですね!
jQueryは全然使いこなせてないですが。。。
function Eratosthenes($) {
var UNKNOWN = -1;
var DEFAULT_LENGTH = 100;
var MIN_LENGTH = 2;
var MAX_LENGTH = 2000;
var self = this;
var list;
var queue;
// 数列を篩にかけます。
// 素数か合成数かが判別できた時点でqueueに入れてます。
this.sieve = function() {
for (var i = 2; i < list.length; i++) {
if (list[i] != UNKNOWN) {
continue;
}
var color = newColor();
list[i] = i;
queue[queue.length] = {n: i, color: color};
if (i * i > list.length) {
continue;
}
for (var j = i * 2; j < list.length; j += i) {
if (list[j] != UNKNOWN) {
continue;
}
list[j] = i;
queue[queue.length] = {n: j, color: color};
}
}
this.visualize(0);
}
// queueの順に判別した様を可視化します。
this.visualize = function(index) {
if (index < queue.length) {
var n = queue[index].n;
if (n == list[n]) {
$('#primes').append(' ' + n);
$('#td' + n).css('border-color', '#ff0000');
}
$('#td' + n).css('background-color', queue[index].color);
setTimeout(function () {self.visualize(index + 1);}, Math.floor(10000/list.length));
}
}
// 色を適当に作成します。
// 薄めの色で隣り合う色がなるべく判別しやすいように。。。
var newColor = (function() {
var times = 0;
return function() {
var color = '#';
for (var i = 0; i < 3; i++) {
var c = times % 3 == i ? 0xFF : (Math.floor(Math.random() * 0x7F) + 0x7F);
color += c.toString(16);
}
times++;
return color;
};
})();
// 初期化します。
var init = function() {
var len = parseInt($('#length').val());
if (isNaN(len)) {
len = DEFAULT_LENGTH;
} else {
len = Math.max(len, MIN_LENGTH);
len = Math.min(len, MAX_LENGTH);
}
$('#length').val(len);
list = new Array(len + 1);
list[0] = 0;
list[1] = 1;
for (var i = 2; i < list.length; i++) {
list[i] = UNKNOWN;
}
$('#nlist').empty();
var tr;
for (var i = 1; i < list.length; i++) {
if (i % 10 == 1) {
tr = $('<tr>');
$('#nlist').append(tr);
}
tr.append($('<td>').attr('id', 'td' + i).text(i));
}
$('#primes').empty();
queue = new Array();
}
init();
}