(*-------------------------------------------------------------------
SIEVE.PAS
エラトステネスの篩で素数を求める Pascal
のプログラムソース。
1230個の素数のテーブルを篩として用意する。このときテーブルの最大の
素数は10007なので、1億までの数値を篩にかけることができる。
探索範囲に配列を設定して、これを篩にかけて素数を抽出する。この探索範
囲を順にずらせていく。
なるべく処理系に依存しないようにするため、出力は標準出力のみとした。
動作を確認したPascal処理系は以下の5種類。
HAPPy v0.3
浅野比富美さんによる、MS-DOS汎用の標準Pascalコンパイラ。
ISO規格に忠実に従った標準Pascalコンパイラ。フリーソフト。
http://www.vector.co.jp/soft/dos/prog/se011503.html
HelloPascal v2.2
菊池鉄太郎氏による、WINDOWS95用のPascalコンパイラ。
Win95上での統合環境が使いやすく、ちょっとPascal言語を使っ
てみたいという人には、とっつきやすい。フリーソフト。
http://www.vector.co.jp/soft/win95/prog/se084406.html
Turbo Pascal v6.0a
Borland(現Inprise)のMS-DOS用Pascalコンパイラ。
MS-DOS用のPascalコンパイラのデファクトスタンダード。
コンパイルの高速さはWindows用の開発環境であるDelphiに
も受け継がれている。
THINK Pascal v4.0
SymantecのMacintosh用Pascalコンパイラ。
Free Pascal v0.99.10
Turbo Pascalと互換性の高いフリーのPascalコンパイラ。
32ビットネイティブコンパイラで、実用的なプログラムの開発が可能。
各種のOS用のものが用意されている(DOS,Win32,OS/2,Linux,Amiga)。
http://www.brain.uni-freiburg.de/~klaus/fpc/
処理系によってinteger型の範囲や、確保できる配列サイズに違いがあるので、
処理系に応じた変更を加えた方がよい場合もある。たとえば、Turbo
Pascal や
Free Pascalでは、integer を longint に変更し、PTabSize =
5000;
LimitSize = 2147000000; と変更することで、21億までの素数の出力が可能に
なる。
---------------------------------------------------------------------*)
program sieve(input,output);
const
PTabSize = 1230;
(* 篩に使う素数テーブルのサイズ *)
TabSize = 10000;
(* 探索範囲に設定する配列のサイズ *)
LimitSize = 100000000;
(* 探索可能な素数の最大値
*)
type
TPArray = array[1..PTabSize] of integer; (*
篩の素数テーブル *)
TTable = array[1..TabSize] of boolean;
(* 探索範囲に設定する配列 *)
var
Max : integer;
(* 求める素数の最大値 *)
P : ^TPArray;
(* 篩の配列へのポインタ *)
Tab : ^TTable;
(* 探索用配列へのポインタ *)
(*--------------------------------------------------------------------
求める素数の最大値を受け取り、TabSizeの倍数になるよう設定し直す
----------------------------------------------------------------------*)
procedure GetRange;
begin
repeat
Write('Input maximum number = '); readln(Max);
if (Max > LimitSize) or (Max < 1) then
Writeln('Illegal value.');
until (Max > 0) and (Max <= LimitSize);
Max := TabSize * ((Max-1) div TabSize + 1);
Writeln('Search primes up to ', Max:1);
end;
(*---------------------------------------------------------------
篩として使う素数テーブルの作成。篩として必要な素数の最大値は
Maxの平方根なので、そこまで作ったら処理を打ち切る。
----------------------------------------------------------------*)
procedure MakeSieve;
var
i, j,
(* ループカウンタ *)
Count : integer; (*
素数の個数のカウンタ *)
begin
New(P);
(* 篩の配列のメモリを確保 *)
P^[1] := 2;
Count := 1;
i := 3;
while Sqr(P^[Count]) < Max do begin
j := 1;
while (Sqr(P^[j]) <= i) and (i mod P^[j]
<> 0) do j := j+1;
if Sqr(P^[j]) > i then begin
Count := Count + 1;
P^[Count] := i;
end;
i := i + 2;
end;
Writeln('Sieve constructed.');
end;
(*---------------------------------------------------------------
合成数を篩でふるい落として、素数を求める処理
----------------------------------------------------------------*)
procedure SearchPrime;
var
Times,
(* 配列を当てはめた回数のカウンタ 0〜
*)
Repeats,
(* 配列を当てはめる回数
*)
OffSet,
(*
配列の添字と素数値を対応させるためのオフセット
*)
i, j,
(* ループカウンタ
*)
Counter : integer; (*
出力した素数の数を数えるカウンタ
*)
begin
New(tab);
(* 配列のメモリを確保 *)
Counter := 0;
(* カウンタの初期化 *)
Repeats := (Max-1) div TabSize;
for Times := 0 to Repeats do begin
OffSet := Times * TabSize;
for i := 1 to TabSize do (*
奇数はtrue,偶数はfalseにセット *)
Tab^[i] := Odd(i);
if Times = 0 then begin
(* 最初だけは別処理 *)
Tab^[1] := false;
Tab^[2] := true;
end;
(*
合成数のふるい落とし。素数の倍数は false
をセット*)
i := 2;
while (Sqr(P^[i]) <= OffSet + TabSize) do
begin
if P^[i] = 0 then
writeln(Sqr(P^[i-1]));
j := (OffSet div P^[i] + 1) *
P^[i];
if not Odd(j) then j := j + P^[i];
if Times = 0 then j := Sqr(P^[i]);
while j <= OffSet + TabSize do
begin
Tab^[j - OffSet] :=
false;
j := j + P^[i] * 2;
end;
i := i + 1;
end;
(* 素数を標準出力に出力する。10個毎に改行する
*)
for i := 1 to TabSize do
if Tab^[i] then begin
(* Tab^[i]がtureのとき OffSet+i は素数 *)
Counter := Counter +
1;
Write(' ', OffSet + i
:1);
if Counter mod 10 = 0
then Writeln;
end;
end;
Writeln;
(* 出力した素数の個数を出力する *)
Writeln(Counter : 1, ' primes found.');
end;
(* メインブロックには全体の処理の流れを書く
*)
begin
GetRange;
(* 探索範囲を受け取る
*)
MakeSieve;
(* 篩を作る
*)
SearchPrime; (*
篩を使って素数を探索・出力する *)
end.