!---------------------------------------------------------------------------
!                  SOSUU.BAS  for (仮称)十進BASIC
! エラトステネスの篩で素数をリストアップするするプログラム。
! 5000個の素数テーブルを篩として用意する。このときテーブルの最大の
! 素数は48611なので、48611^2(約23億)までの数値を篩にかけることが
! できる。実際には配列の添字が32ビット整数の制限を受けるので、上限
! は 2147000000 までとしてある。出力可能な素数の個数は1億強である。
! 探索範囲に配列を設定して、これを篩にかける。この探索範囲を順に
! ずらせていく。配列サイズは TabSize で設定する。TabSizeは実行環
! 境に合わせて変更する事ができるが、偶数でなければならない。
! 結果は、指定したファイルにテキストファイルとしてに出力される。
! 同名のファイルがあっても無条件に上書きするので注意のこと。
! ファイル名入力時にリターンキーのみ押すと画面に出力する。
! Maxを21億にしたときには、出力するファイルサイズは1GB強になる。
!---------------------------------------------------------------------------

! 初期設定
option arithmetic native              ! 十進BASICの数値モードの指定

! 変数の宣言
declare string  FileName$             ! 出力するファイル名
declare numeric TabSize, PSize        ! 配列サイズの設定値
declare numeric Max                   ! 求める素数の上限値
declare numeric StartTime             ! 計算開始時刻
declare numeric i, j, k               ! ループカウンタ
declare numeric Count                 ! 素数の数のカウンタ
declare numeric ArrayEnd, ArrayEndSqr ! 配列の最後の添字とその平方根
declare numeric StartPoint            ! 消去すべき素数の倍数の開始点

! 配列サイズの設定
let PSize   = 5000                    ! 篩として使う素数テーブルの大きさ
let TabSize = 10000                   ! 探索対象にする配列の大きさ(偶数)

! 配列の宣言
dim p(PSize)                          ! 篩となる素数テーブルの配列の宣言
dim tab(TabSize)                      ! 探索に使う配列

!--------------------------------------------------------
! 求める素数の最大値と出力ファイル名を受け取る
!--------------------------------------------------------
input prompt "求める素数の最大サイズを指定してください": Max
let Max = TabSize*(int((Max-1)/TabSize)+1)
if Max > 2147000000 then
   print "指定された値が大きすぎます。Max=2147000000 に設定します"
   let Max = 2147000000
end if
print Max; "までの素数を探索します"
Line input prompt "ファイル名を入力してください": FileName$
if Filename$ = "" then print "ファイルではなく画面に出力します"
let StartTime = Time                  ! 計算開始時間の記録

!-----------------------------------------------------------------------
!ファイル名が指定されているときはファイルを開いておく。無条件に上書き。
!-----------------------------------------------------------------------
if Filename$ <> "" then
   OPEN #1: NAME FileName$, RECTYPE INTERNAL
   ERASE #1
end if

!----------------------------------------------------------------------
! 篩の作成。√Maxまでの素数の値を、篩として使う配列 p に代入する
!----------------------------------------------------------------------
let P(1) = 2
let Count = 1
let i = 3
do while P(Count)^2 < Max
   let j = 1
   do while (P(j)^2 <= i) and (mod(i, P(j)) <> 0)
      let j = j+1
   loop
   if P(j)^2 > i then
      let Count = Count + 1
      let P(Count) = i
   end if
   let i = i + 2
loop
print "Sieve constructed."

!---------------------------------------------------------------------------
! ここからがメイン処理。篩を使って、素数を求めていく
!---------------------------------------------------------------------------
let Count = 0                         ! リストした素数の個数の数えるカウンタ
for i = 1 to Max step TabSize
   let ArrayEnd = i + TabSize - 1
   let ArrayEndSqr = Int(SQR(ArrayEnd))
   redim tab(i to ArrayEnd)           ! 添字範囲を変更、配列要素は0に初期化
   for j = i to ArrayEnd step 2       ! 奇数のみ候補として残す(1を代入する)
      let tab(j) = 1
   next j
   if i = 1 then                    ! i = 1 のときだけの例外処理
      let tab(1) = 0                ! 1 は素数でないので tab(1)には 0 を代入
      let tab(2) = 1                ! 2 は素数なので     tab(2)には 1 を代入
   end if

   ! 合成数(=素数の倍数)をふるい落とす(=0を代入する)処理
   let j = 2
   do while p(j) <= ArrayEndSqr
      if i = 1 then
         let StartPoint = p(j)^2
      else
         let StartPoint = p(j) * (int((i-1) / p(j)) + 1)
         if mod(StartPoint,2)=0 then
            let Startpoint = StartPoint + p(j)
         end if
      end if
      for k = StartPoint to ArrayEnd step 2*p(j)
         let tab(k) = 0
      next k
      let j = j + 1
   loop

   ! 素数の出力。配列の添字が素数であるときその配列要素は1になっている。
   for j = i to ArrayEnd
      if tab(j) = 1 then          ! tab(j)=1 のとき j は素数
         let Count = Count + 1
         if FileName$ = "" then   ! ファイル名が指定されていないときは画面出力
            print j;
            if Mod(Count,10)=0 then print
         else                     ! 指定されたファイルに出力
            write #1: j,
            if Mod(Count,10)=0 then write #1:
         end if
      end if
   next j

   ! 素数をファイルに出力するときは画面に途中経過を表示
   if FileName$ <> "" then
      print ArrayEnd; "integers checked.  "; Count; "primes found."
   end if
next i

! 終了メッセージの出力
if FileName$ <> "" then                           ! ファイル出力の終了処理
   write #1:
   write #1: Count, "primes found."
   close #1
end if
print
print "Finished.  "; Count; "primes found.  ";
print using "-----%.#": Time - StartTime;         ! 計算所用時間の表示
print " sec."
END

三崎吉剛のページに戻る