究極の素数を求める旅(4)

検定ミスが見つかった
  移植するのに当たって、現在まで得られている素数を再度調べた。と、実は一部で素数を飛ばして計算していることが解った。
 今回のプログラムは完全積み上げ型を指向していたので何処かでミスすると以後の計算が全て間違った結果になる危険性が有った。だから、基礎になる今まで得た素数を再度検定したのだが何故か100万個あたりが怪しい。ここは90万個あたりからデータが欠落しているのだ。ここまで戻って新しいプログラムを動かそうと思ったのは既に300万個まで来ていた段階なのだが、計算ミスはしょうがない。現在ここからリスタートしている。
それにしても一日かかって10万件しか計算出来ない。このコラムを書き始めた状態に戻るには1ヶ月くらい時間が必要かもしれない。そんな感じで再度素数計算を始めた。

今回のプログラムの基本的考え方
 経験から思ったほど数字が大きくなっても素数は減らない。「思ったほど」ってのは個人差があると思うが最初の頃は「世界最高の素数ってパソコンが2、3日動いた後にぱっと画面に表示されるのではないか」と思っていた。しかし、実際には最初数千までの段階では急激に素数の出現率が下がるが、その後はほとんど同じ様な割合で素数が出現する。
もっとも理論通りに少しは減る。しかしその減り方は劇的では無く、徐々にって感じだ。
そこで見つかった素数を貯めておいても貯めるファイルが大きくなってパソコンの外部メモリーをオーバーフローさせてしまう。今回使えるパソコンのハードディスクは450Mbyte程有るので、得られた素数を貯めるのは十分だ。ただし、途中での計算ミス等でもリスタートできるように結果を1ファイルに集約させるのでは無く分散させたいと思う。
また、1Mbyteのramファイルが使えるのでこれは利用しない手は無い。ramファイルの利用によってハードディスクを回さなくてもファイルを書き出せる。ただ、その上限は1Mbyteまでだ。
 そこで考えたのは得られた素数をテーブルとしてメモリーに許される上限まで読み込む。これはおおむね8000個までであった。それ以上の素数はファイルとして必要が有れば読み込む。もちろんこの読み込まれる素数は既に得られた素数でもある。得られた素数はramファイルの中でappend(追加)するファイルに書き込む。このファイルを時々ハードディスクに待避して10万件毎のファイルとして蓄積する。
そんな方法で作られたのが以下のプログラム
10 'save "sosu.bas",a
20 '**************************************************
30 '* BASICの標準関数での最大の素数を求める  *
40 '**************************************************
50 DEFDBL A-S
60 STIME$=TIME$
70 MAX=8000
80 DIM SOSU(MAX)
90 DIM FIL$(100)
100 GOSUB *STPRG
110 A=A+2
120 SOSU=0
130 GOSUB *SOSUCHK
140 IF SOSU=1 THEN ELSE GOTO 290
150 DMAX=DMAX+1
160 AS=A-APRO
170 IF AS>100000! THEN GOTO 190
180 IF AS>AMAX THEN AMAX=AS
190 rtu=dmax/a
191 PRINT USING "No=##,###,### A=###,###,### pro=###";DMAX,A,AS;
200 PRINT USING " max=#### %=#.##### ";AMAX,rtu*100;
210 PRINT USING "&      & &      &";STIME$,TIME$
220 APRO=A
230 OPEN "C:\0_sosu.dat" FOR APPEND AS #1
240 PRINT #1,RIGHT$(STR$(A),LEN(STR$(A))-1)+",";
250 CLOSE #1
260 A$=INKEY$
270 IF A$="Z" THEN GOTO 300
280 IF A$="z" THEN GOTO 300
290 GOTO 110
300 *FIN
310 CLOSE
320 END
330 *STPRG
340 '**************************************************
350 '* 初期の既知の素数を読み込む          *
360 '**************************************************
370 PRINT "Phase 1 テーブル(1)読み込み"
380 OPEN "a:\bas\LOG\00008K.dat" FOR INPUT AS #1
390 IF EOF(1) THEN GOTO 450
400 INPUT #1,SOSU
410 DMAX=DMAX+1
420 IF DMAX>MAX THEN GOTO 450
430 SOSU(DMAX)=SOSU
440 GOTO 390
450 CLOSE #1
460 PRINT "Phase 1 テーブル(1)読み込み終了"
470 PRINT "Phase 2 テーブル(2)読み込み開始"
480 OPEN "C:\0_sosu.dat" FOR INPUT AS #1
491 DMAX=1408000                             '* 設定変更注意
500 IF EOF(1) THEN GOTO 550
510 INPUT #1,ASOSU
520 DMAX=DMAX+1
530 A=ASOSU
540 GOTO 500
550 CLOSE
560 PRINT "Phase 2 テーブル(2)読み込み終了"
570 FIL$(1)="LOG\00108K.dat"
580 FIL$(2)="LOG\00208K.dat"
590 FIL$(3)="LOG\00308K.dat"
600 FIL$(4)="LOG\00408K.dat"
610 FIL$(5)="LOG\00508K.dat"
620 FIL$(6)="LOG\00608K.dat"
630 FIL$(7)="LOG\00708K.dat"
640 FIL$(8)="LOG\00808K.dat"
650 FIL$(9)="LOG\00908K.dat"
660 FIL$(10)="LOG\01008K.dat"
670 FIL$(11)="LOG\01108k.dat"
680 FIL$(12)="LOG\01208K.dat"
690 FIL$(13)="LOG\01308K.dat"
700 FIL$(14)="LOG\01408K.dat"
710 FIL$(15)="LOG\01508K.dat"
720 FIL$(16)="LOG\01608K.dat"
730 FIL$(17)="LOG\01708K.dat"
740 FIL$(18)="LOG\01808K.dat"
750 FIL$(19)="LOG\01908K.dat"
760 FIL$(20)="LOG\02008K.dat"
770 FIL$(21)="LOG\02108K.dat"
780 FIL$(22)="LOG\02208K.dat"
790 FIL$(23)="LOG\02308K.dat"
800 FIL$(24)="LOG\02408K.dat"
810 FIL$(25)="LOG\02508K.dat"
820 FIL$(26)="LOG\02608K.dat"
830 FIL$(27)="LOG\02708K.dat"
840 FIL$(28)="LOG\02808K.dat"
841 FIL$(29)="LOG\02908K.dat"
850 RETURN
860 *SOSUCHK
870 '**************************************************
880 '* テーブルを利用して素数を検定する       *
890 '**************************************************
900 FOR ZI=2 TO MAX
920     AW=A-INT(A/SOsu(zi))*SOsu(zi)
930     IF AW=0 THEN GOTO 1140
940 NEXT ZI
950 '**************************************************
960 '* ファイルの素数で値を検定する         *
970 '**************************************************
980 IF A>SOSU(7999)*SOSU(8000) THEN ELSE GOTO 1120
990 FILNO=0
1000 FILNO=FILNO+1
1010 IF FIL$(FILNO)="" THEN GOTO 1120
1020 PRINT FIL$(FILNO)+" open"
1030 OPEN FIL$(FILNO) FOR INPUT AS #1
1040 IF EOF(1) THEN GOTO 1100
1050 INPUT #1,ASOSU
1060 IF ASOSU > A/2 THEN GOTO 1120
1070 AW=A-INT(A/ASOSU)*ASOSU
1080 IF AW=0 THEN GOTO 1130
1090 GOTO 1040
1100 CLOSE #1
1110 GOTO 1000
1120 SOSU=1
1130 CLOSE #1
1140 RETURN
  戻る 次へ

今来たページに戻る

2002.05.30 Mint