プログラムの質問

 投稿者:GAI  投稿日:2014年11月29日(土)08時55分1秒
  for a=1 to 100
next a
ならa=1,2,3,・・・,100
に渡って変化するところを
素数だけに限って変化させるにはどうしたらいいのでしょうか?
a=2,3,5,7,11,13,・・・,97
での変化で動かしたい。
 

Re: プログラムの質問

 投稿者:山中和義  投稿日:2014年11月29日(土)09時56分56秒
  > No.3561[元記事へ]

GAIさんへのお返事です。

> for a=1 to 100
> next a
> ならa=1,2,3,・・・,100
> に渡って変化するところを
> 素数だけに限って変化させるにはどうしたらいいのでしょうか?
> a=2,3,5,7,11,13,・・・,97
> での変化で動かしたい。

素数は、通常のプログラム言語では、サポートされていませんので、
次のような関数ルーチンをつくり、素数判定を行います。
また、素数判定にはいくつかのアルゴリズムがあります。


OPTION ARITHMETIC RATIONAL !多桁整数
FOR P=2 TO 100
   IF P=prmdiv(P) THEN !PrimeQ

      PRINT P

   END IF
NEXT P
END

!ubasic.LIBより抜粋

EXTERNAL FUNCTION prmdiv(n) !1より大きな最小の約数 ※nは1より大きな整数
OPTION ARITHMETIC RATIONAL !多桁整数
IF MOD(n,2)=0 THEN !2の倍数
   LET prmdiv=2
ELSEIF MOD(n,3)=0 THEN !3の倍数
   LET prmdiv=3
ELSE
   FOR i=5 TO INTSQR(n) STEP 6
      IF MOD(n,i)=0 THEN !5,11,17,23,29,…
         LET prmdiv=i
         EXIT FUNCTION
      ELSEIF MOD(n,i+2)=0 THEN !7,13,19,25,31,…
         LET prmdiv=i+2
         EXIT FUNCTION
      END IF !+1,+3,+5は2の倍数(偶数)、+1,+4は3の倍数、+5は5の倍数
   NEXT i
   LET prmdiv=n !その数自身
END IF
END FUNCTION


 

Re: プログラムの質問

 投稿者:白石和夫  投稿日:2014年11月30日(日)10時39分13秒
  > No.3561[元記事へ]

ある数以下のすべての素数について順に調べたければ,エラトステネスの篩で素数が判定されたところで調査目的の副プログラムを呼び出して

100 DECLARE EXTERNAL SUB test
110 ! エラトステネスの篩
120 DIM s(1000)
130 MAT s=ZER
140 FOR i=2 TO 1000
150    IF s(i)=0 THEN
160       CALL test(i)
170       FOR  j=i^2 TO 1000 STEP i
180          LET s(j)=1
190       NEXT j
200    END IF
210 NEXT i
220 END
1000 EXTERNAL SUB test(p)
1010 PRINT p
1020 END SUB

のようにすればよいのですが,この場合,エラトステネスの篩が主で調査目的の副プログラムが従の関係になります。
主客を転倒させて調査目的のプログラムを主に持っていきたいときは,Full BASICのモジュールを用いて

100 DECLARE EXTERNAL FUNCTION Primes.NextPrime
110 DO
120    PRINT nextPrime
130 LOOP
140 END
1000 MODULE Primes
1010 PUBLIC FUNCTION NextPrime
1020 SHARE NUMERIC s(2 TO 100000), CurPrime
1030 MAT s=ZER
1040 LET CurPrime=1
1050 EXTERNAL FUNCTION NextPrime
1060    DO
1070       LET CurPrime=CurPrime+1
1080    LOOP UNTIL s(CurPrime)=0
1090    LET NextPrime=CurPrime
1100    FOR j=CurPrime^2 TO 100000 STEP CurPrime
1110       LET s(j)=1
1120    NEXT j
1130 END FUNCTION
1140 END MODULE

のように構成することもできます(アルゴリズムはエラトステネスの篩で変わりません)。モジュール内の変数は静的なので,NextPrime関数が呼び出されたとき,前回のCurPrimeが残っていて次の素数が求められます。

ただし,どちらを採用する場合でも,素数の上限をあらかじめ指定しておく必要があります。


 

Re: プログラムの質問

 投稿者:白石 和夫  投稿日:2014年12月 4日(木)10時24分33秒
  NextPrimeを次の素数を生成する副プログラムとし,CurPrimeを広域変数にしたほうが扱いやすいかもしれません(変数のCurPrimeは何度でも参照可能)。

100 DECLARE EXTERNAL SUB Primes.NextPrime
110 DECLARE EXTERNAL NUMERIC Primes.CurPrime
120 DO
130    CALL NextPrime
140    PRINT CurPrime
150 LOOP
160 END
1000 MODULE Primes
1010 PUBLIC SUB NextPrime
1020 PUBLIC NUMERIC CurPrime
1030 SHARE NUMERIC s(2 TO 100000)
1040 MAT s=ZER
1050 LET CurPrime=1
1060 EXTERNAL SUB NextPrime
1070    DO
1080       LET CurPrime=CurPrime+1
1090    LOOP UNTIL s(CurPrime)=0
1100    FOR j=CurPrime^2 TO 100000 STEP CurPrime
1110       LET s(j)=1
1120    NEXT j
1130 END SUB
1140 END MODULE

なお,限界に達するとエラーとなって止まります。エラーメッセージを出したくないときは,1080行前後にCurPrimeの値を検査するコードを追加してください。

 

Re: プログラムの質問

 投稿者:nagram  投稿日:2014年12月 9日(火)14時28分39秒
  > No.3566[元記事へ]

CurPrimeを広域変数にすると主プログラム内でCurPrimeの値を変更することが可能となり、CurePrime^2より小さく変更すれば、次にNextPrimeを実行したときには変更したCurPrimeの次の素数が得られます。
この性質を利用して、引数より大きな最小の素数を返す関数を作成しました。UBASICの関数nxtprm(n)と同じ機能です。
また、2と3の倍数をあらかじめ除き、配列sの大きさを3分の1に圧縮しました。

REM 関数 NextPrime(n) … nより大きい最小の素数。nは整数でなくともよい。
DECLARE EXTERNAL FUNCTION Primes.NextPrime
LET p=1
FOR i=1 TO 30
   LET p=NextPrime(p)
   PRINT p
NEXT i
RANDOMIZE
FOR i=1 TO 30
   LET a=INT(100000*RND)
   LET p=NextPrime(a)
   PRINT a;p
NEXT i
PRINT NextPrime(99990) ! maxn=100000のときの最大素数は99991。これより大きい引数はエラー。
END
!
MODULE Primes
PUBLIC FUNCTION NextPrime
SHARE NUMERIC s(33333),maxn,MaxPrime ! 配列sのサイズは変更可能だが、必ず定数で指定。
LET maxn=3*SIZE(s)+1 ! maxnまでの素数に対応
MAT s=ZER
WHEN EXCEPTION IN
   FOR i=8 TO maxn STEP 10 ! 5の倍数
      LET s(i)=1
      LET s(i+3)=1
   NEXT i
USE
END WHEN
LET MaxPrime=5
!          j=5,7,11,13,17,19,23,25,29,31,35,37,41,43,47,49,53,55,59,61,65,67,71,73,77,79
!   INT(j/3)=1,2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
!s(INT(j/3))=0,0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0
EXTERNAL FUNCTION NextPrime(n)
   IF n<5 THEN
      LET NextPrime=5
      IF n<3 THEN LET NextPrime=3
      IF n<2 THEN LET NextPrime=2
      EXIT FUNCTION
   END IF
   LET n=INT(n)
   LET k=MOD(n,6)
   IF k<>1 AND k<>5 THEN LET n=n-ABS(k-1)
   IF n<=MaxPrime^2 THEN CALL PrimeCheck(n)
   !
   IF MOD(MaxPrime,6)=1 THEN LET add=4 ELSE LET add=2
   WHEN EXCEPTION IN
      DO ! エラトステネスの篩
         LET ex=1
         DO
            LET MaxPrime=MaxPrime+add
            LET add=6-add
         LOOP UNTIL s(INT(MaxPrime/3))=0
         LET ex=0
         FOR j=MaxPrime^2 TO maxn STEP 6*MaxPrime
            LET s(INT(j/3))=1
            IF MOD(j+2*MaxPrime,3)>0 THEN LET s(INT((j+2*MaxPrime)/3))=1 ELSE LET s(INT((j+4*MaxPrime)/3))=1
         NEXT j
      LOOP UNTIL MaxPrime>=INT(SQR(n))
   USE
      IF ex=1 THEN EXIT FUNCTION ! エラー NextPrime=0
   END WHEN
   CALL PrimeCheck(n)
   SUB PrimeCheck(p) ! pより大きい素数の検索
      IF MOD(p,6)=1 THEN LET add=4 ELSE LET add=2
      WHEN EXCEPTION IN
         DO
            LET p=p+add
            LET add=6-add
         LOOP UNTIL s(INT(p/3))=0
         LET NextPrime=p
      USE ! エラー NextPrime=0
      END WHEN
      EXIT FUNCTION
   END SUB
END FUNCTION
END MODULE
 

戻る