新しく発言する EXIT インデックスへ
ランダム数の周期

  ランダム数の周期 yoichiro 2007/06/08 00:13:53 
  現在のバージョンでは, 白石 和夫 2007/06/08 14:32:38 
  十進BASICの組込み関数RNDにより発生する乱... 荒田浩二 2007/06/08 18:58:39 
   ├!何故か不明、ときどき一致しない時がある。... SECOND 2007/06/10 19:59:10  (修正1回)
   │├出張で返事おそくなりました。 yoichiro 2007/06/11 09:27:14  (修正1回)
   │└RANDOMIZE文がPCの内部時計を参照し種を与え... 荒田浩二 2007/06/12 15:45:57  (修正1回)
   │ ├補足 荒田浩二 2007/06/12 16:50:44 
   │ │└RANDOMIZEの実体は 白石 和夫 2007/06/12 17:32:44  (修正2回)
   │ │ └RANDOMIZEも種が、TIME関数と同一と、いうこ... SECOND 2007/06/12 18:00:26  (修正1回)
   │ │  └MyTimeは拡張精度なので,それが差がでる原... 白石 和夫 2007/06/12 18:16:23 
   │ │   └先生のリストで、同値のMytimeに挟まれるMy... SECOND 2007/06/12 22:06:23  (修正5回)
   │ │    └整数丸めコントロール・ワードが勝手にゆら... 白石 和夫 2007/06/13 07:23:02  (修正2回)
   │ │     └私のパソコンでも荒田氏と同様の時刻の規則... SECOND 2007/06/13 07:53:00  (修正2回)
   │ └DELETED  SECOND  2007/06/12 17:23:39  (削除)
   └リストの中で、"田"が"川"になっていた事を... SECOND 2007/06/18 06:52:15 

  ランダム数の周期 yoichiro 2007/06/08 00:13:53  ツリーへ

ランダム数の周期 返事を書く ノートメニュー
yoichiro <lrmllemwxh> 2007/06/08 00:13:53
十進BASICでは、RNDを用いた時
「使用乱数の種類と周期」
は、どのようなものになるのでしょうか。

また、十進BASICを使用した旨を論文に載せる場合、
英語ではどのように表記すればよろしいでしょうか。

  現在のバージョンでは, 白石 和夫 2007/06/08 14:32:38  ツリーへ

Re: ランダム数の周期 返事を書く ノートメニュー
白石 和夫 <fbdfvqwhki> 2007/06/08 14:32:38
現在のバージョンでは,
function random:extended;
begin
result:=System.Random;
end;
のようにDelphiの乱数をそのまま利用しています。
以前のバージョンでは,
function random:extended;
const
a=16807.0;
m=2147483647.0;
var
temp:extended;
begin
temp:=a*seed;
seed:=temp-m*int(temp/m);
random:=seed/m
end;
で計算していました。
十進BASICでは,モジュールの機能を用いて次のようにすれば,自分専用の乱数を持つことができます。
100 OPTION ARITHMETIC NATIVE
110 DECLARE EXTERNAL FUNCTION math.random
120 DECLARE EXTERNAL SUB math.randomize
130 CALL RANDOMIZE
140 DECLARE NUMERIC i
150 FOR i=1 TO 20
160 PRINT random
170 NEXT i
180 END
190
200 MODULE math
210 MODULE OPTION ARITHMETIC NATIVE
220 SHARE NUMERIC seed,a,m
230 PUBLIC FUNCTION random
240 PUBLIC SUB RANDOMIZE
250 LET seed=12345
260 LET a=16807.0
270 LET m=2147483647.0
280 EXTERNAL FUNCTION random
290 DECLARE NUMERIC temp
300 LET temp=a*seed
310 LET seed=temp-m*INT(temp/m)
320 LET random=seed/m
330 END FUNCTION
340 EXTERNAL SUB RANDOMIZE
350 LET seed = TIME
360 END SUB
370 END MODULE
 留意点は,RNDはFull BASICの予約語なので,利用者定義関数の名前にRNDを用いることができないことです。
 なお,十進BASICの英語名はDecimal BASICとしています。

  十進BASICの組込み関数RNDにより発生する乱... 荒田浩二 2007/06/08 18:58:39  ツリーへ

Re: ランダム数の周期 返事を書く ノートメニュー
荒田浩二 <knrztrhoel> 2007/06/08 18:58:39
 十進BASICの組込み関数RNDにより発生する乱数列は、2147483647を法、16807を乗数、54321を種として線形合同法(乗算合同法)により生成されたものです。
法の2147483647(=2^31-1)と乗数の16807(=7^5)は、良い乱数列を生成する組として知られているものです。
種の54321(=3*19*953)は開発者による任意の値と思われます。

 RND関数で得られる乱数列の周期は2147483646(=2^31-2)です。
 また、RND関数は周期の二分の一となる1073741823個(=2^30-1個)の乱数を発生した後、当初の乱数との和が1となる数値を順次発生します。
ですから、実用上の周期は1073741823(=2^30-1)でしょう。
  
 また、十進BASICのRANDOMIZE文はTIME関数を利用し、種を 16807*(100*TIME+1) で与えています。


 次は、白石先生のプログラムを利用し、関数randomが組込み関数RNDと同様の値を返すようにしたものです。
少しわかりづらいですが、148行のRANDOMIZEはRANDOMIZE文で、それ以外は副プログラム名です。
 250行がRANDOMIZE文を実行しない時のRND関数の初期の種、350行がRANDOMIZE文で与えられる種です。

100 OPTION ARITHMETIC NATIVE
110 DECLARE EXTERNAL FUNCTION math.random
120 DECLARE EXTERNAL SUB math.randomize
130 !CALL RANDOMIZE
140 DECLARE NUMERIC i,j
142 FOR i=1 TO 5
143 PRINT random;RND
144 NEXT i
145 PRINT
146 FOR j=1 TO 4
147 CALL RANDOMIZE
148 RANDOMIZE
150 FOR i=1 TO 3
160 PRINT random;RND
170 NEXT i
172 PRINT
173 WAIT DELAY 0.25
174 NEXT j
180 END
190
200 MODULE math
210 MODULE OPTION ARITHMETIC NATIVE
220 SHARE NUMERIC seed,a,m
230 PUBLIC FUNCTION random
240 PUBLIC SUB RANDOMIZE
250 LET seed=54321 ! 初期の種
260 LET a=16807.0
270 LET m=2147483647.0
280 EXTERNAL FUNCTION random
290 DECLARE NUMERIC temp
300 LET temp=a*seed
310 LET seed=temp-m*INT(temp/m)
320 LET random=seed/m
330 END FUNCTION
340 EXTERNAL SUB RANDOMIZE
350 LET seed = 16807*(100*TIME+1) ! RANDOMIZE文で与えられる種
360 END SUB
370 END MODULE
 

   ├!何故か不明、ときどき一致しない時がある。... SECOND 2007/06/10 19:59:10  (修正1回) ツリーへ

Re: 十進BASICの組込み関数RNDにより発生する乱... 返事を書く ノートメニュー
SECOND <cszcthjjdj> 2007/06/10 19:59:10 ** この記事は1回修正されてます
!何故か不明、ときどき一致しない時がある。
!時刻合せが、これでも不十分なのか。

!ランダム関数Viewer

OPTION ARITHMETIC NATIVE !モジュールと揃える。
DECLARE EXTERNAL FUNCTION math.random !モジュール内登録
DECLARE EXTERNAL SUB math.randomize !モジュール内登録
DECLARE EXTERNAL FUNCTION math2.random !モジュール内登録
DECLARE EXTERNAL SUB math2.randomize !モジュール内登録

DO
LET t0=TIME
PRINT TIME
CALL math.RANDOMIZE
CALL math2.RANDOMIZE
RANDOMIZE
LOOP UNTIL t0=TIME
PRINT TIME

OPTION BASE 0
DIM sum(500),sum2(500),sum3(500)

SET WINDOW -20, 520, -1, 5.5
SET LINE COLOR 5
FOR i=0 TO 5
FOR j=2 TO 10
PLOT LINES:-1,LOG10(j)+i; 501,LOG10(j)+i
NEXT j
NEXT i
SET COLOR MIX(15) 0.3,0.3,0.3
DRAW grid0(250,2)
PLOT TEXT,AT 300, -0.5: "白石先生、教材サンプル"
PLOT TEXT,AT 300, 1.5: "荒田氏、RND 等価乱数"
PLOT TEXT,AT 300, 3.5: "現在の十進、内蔵 RND"

SET LINE COLOR 1
SET TEXT FONT "",20
SET TEXT BACKGROUND "OPAQUE"
LET y0=LOG10(0.6)

FOR i=1 TO 1000
LET x=INT(500*math.random)
LET x2=INT(500*math2.random)
LET x3=INT(500*RND)
LET sum(x)=sum(x)+1
LET sum2(x2)=sum2(x2)+1
LET sum3(x3)=sum3(x3)+1
PLOT LINES:x,y0; x,LOG10(sum(x))
PLOT LINES:x2,y0+2; x2,LOG10(sum2(x2))+2
PLOT LINES:x3,y0+4; x3,LOG10(sum3(x3))+4
PLOT TEXT,AT 100, -0.7: STR$(i)
IF MOD(i,10)=0 THEN WAIT DELAY 100/(i+100)
NEXT i

END

!-----白石先生、教材サンプル
MODULE math
MODULE OPTION ARITHMETIC NATIVE
SHARE NUMERIC seed, a, m
PUBLIC FUNCTION random
PUBLIC SUB RANDOMIZE
LET seed= 12345
LET a= 16807.0
LET m= 2147483647.0
EXTERNAL FUNCTION random
DECLARE NUMERIC temp
LET temp= a*seed
LET seed= temp-m*INT(temp/m)
LET random= seed/m
END FUNCTION
EXTERNAL SUB RANDOMIZE
LET seed= TIME
END SUB
END MODULE

!-----荒田氏、RND 等価乱数
MODULE math2
MODULE OPTION ARITHMETIC NATIVE
SHARE NUMERIC seed,a,m
PUBLIC FUNCTION random
PUBLIC SUB RANDOMIZE
LET seed=54321 ! 初期の種
LET a=16807.0
LET m=2147483647.0
EXTERNAL FUNCTION random
DECLARE NUMERIC temp
LET temp=a*seed
LET seed=temp-m*INT(temp/m)
LET random=seed/m
END FUNCTION
EXTERNAL SUB RANDOMIZE
LET seed = 16807*(100*TIME+1) ! RANDOMIZE文で与えられる種
END SUB
END MODULE

   │├出張で返事おそくなりました。 yoichiro 2007/06/11 09:27:14  (修正1回) ツリーへ

Re: !何故か不明、ときどき一致しない時がある。... 返事を書く ノートメニュー
yoichiro <lrmllemwxh> 2007/06/11 09:27:14 ** この記事は1回修正されてます
出張で返事おそくなりました。
御返事ありがとうございました。

   │└RANDOMIZE文がPCの内部時計を参照し種を与え... 荒田浩二 2007/06/12 15:45:57  (修正1回) ツリーへ

Re: !何故か不明、ときどき一致しない時がある。... 返事を書く ノートメニュー
荒田浩二 <knrztrhoel> 2007/06/12 15:45:57 ** この記事は1回修正されてます
RANDOMIZE文がPCの内部時計を参照し種を与えていることは間違いないのですが、どうもTIME関数とは違う方法で時刻を取得しているようです。

RANDOMIZE文では通常 16807*(100*TIME+1) の数値式で種を与えているはずですが、RANDOMIZE文を実行する時刻によっては2%〜50%程度の割合で、16807*(100*(TIME-0.01)+1) という数値式で種を与えることがあります。

もっともこのことは「疑似乱数の系列の出発点を予測できないものにする。」というRANDOMIZE文の本来の目的からすれば、むしろ好ましいことと言えるでしょう。

次のプログラムは、RND関数と同様の値を返す関数rnd2を定義し、両者に相違が生じた場合に修正した種を与えるようにしたものです。


REM ** RANDOMIZE文で与える種との相違 **
LET seed=54321 ! RANDOMIZE文を実行しないときの初期の種
FUNCTION rnd2 ! RND関数と同様の値を返す関数
LET seed=MOD(16807*seed,2147483647) ! 16807=7^5 , 2147483647=2^31-1
LET rnd2=seed/2147483647
END FUNCTION
LET c=0
LET t0=TIME
DO WHILE t0+1>TIME ! 1秒間実施
DO ! RANDOMIZE文の前後でTIME関数の値が更新されていないことを確認
LET t1=TIME
RANDOMIZE
LET t2=TIME
LOOP UNTIL t1=t2
LET seed=16807*(100*t2+1) ! RANDOMIZEと同様の種を与える数値式
LET r=RND
LET r2=rnd2
IF ABS(r-r2)>1E-12 THEN ! RNDとrnd2の値が違う時
PRINT USING "TIME #####.## #####.##":t1,t2
PRINT USING "RND = .############### , ##########(種)":r,INT(r*2147483647+0.5)
PRINT USING "rnd2= .############### , ##########(seed)":r2,seed
LET seed=16807*(100*(t2-0.01)+1) ! 修正した種を与える数値式
LET r3=rnd2
PRINT USING "修正= .############### , ##########(seed)":r3,seed
PRINT
LET c=c+1
END IF
WAIT DELAY 0.02
LOOP
PRINT "相違";c;"回"
END

   │ ├補足 荒田浩二 2007/06/12 16:50:44  ツリーへ

Re: RANDOMIZE文がPCの内部時計を参照し種を与え... 返事を書く ノートメニュー
荒田浩二 <knrztrhoel> 2007/06/12 16:50:44
補足

上に投稿した「** RANDOMIZE文で与える種との相違 **」というプログラムを実行すると、「相違 0 回」と出力される時は数回繰り返しても同じ結果になると思います。
どうもRANDOMIZE文を実行する時刻によって、この相違が生じるかしないかが決定されるようです。
そして、相違が生じる時刻には規則性がありそうです。

次のプログラムは、RANDOMIZE文が通常とは違う種を与えるか与えないかを調査した結果を出力するものです。
「なし」の時間帯に上のプログラムを実行しても「相違 0 回」になります。

参考までに、この調査を実施したのは2006年12月5日ですので十進BASICのバージョンもその時点のものです。
その時のPCのOSは、Windows XP SP2 です。
別のPCやOSでは、違う結果になるかもしれません。

なぜこのような結果になるのか、どなたか説明できる方いらっしゃいますか?


REM ** RANDOMIZE文調査結果 **
DECLARE FUNCTION times$
PRINT "RANDOMIZE文を実行して与えられる種が、"
PRINT "16807*(100*TIME+1)と相違する場合の有無"
PRINT
PRINT USING "########### (#####.##) >#####":"実行時刻","TIME","相違"
FOR i=8 TO 22
LET t1=0.01*2^i
LET t2=2^(i-6)
PRINT USING "########### (#####.##)〜 なし":times$(t1),t1
PRINT USING "########### (#####.##)〜 あり":times$(t2),t2
NEXT i
LET t1=0.01*2^i
PRINT USING "########### (#####.##)〜 なし":times$(t1),t1
FUNCTION times$(p) ! TIME$で秒を小数まで表示
LET hh$=USING$("%%",INT(p/3600))
LET mm$=USING$("%%",MOD(INT(p/60),60))
LET ssss$=USING$("%%.##",MOD(p,60))
LET times$=hh$&":"&mm$&":"&ssss$
END FUNCTION
END

   │ │└RANDOMIZEの実体は 白石 和夫 2007/06/12 17:32:44  (修正2回) ツリーへ

Re: 補足 返事を書く ノートメニュー
白石 和夫 <fbdfvqwhki> 2007/06/12 17:32:44 ** この記事は2回修正されてます
RANDOMIZEの実体は
procedure MyRandmize;
var
x:extended;
begin
seed:=int(mytime*100)+1;
x:=random;
end;
となっています。
MytimeはTIME関数の実体です。

   │ │ └RANDOMIZEも種が、TIME関数と同一と、いうこ... SECOND 2007/06/12 18:00:26  (修正1回) ツリーへ

Re: RANDOMIZEの実体は 返事を書く ノートメニュー
SECOND <cszcthjjdj> 2007/06/12 18:00:26 ** この記事は1回修正されてます
RANDOMIZE も 種が、TIME関数と同一と、いうことですか。
少数下第3位目の、システム時刻は、どう処理されているのでしょうか。

   │ │  └MyTimeは拡張精度なので,それが差がでる原... 白石 和夫 2007/06/12 18:16:23  ツリーへ

Re: RANDOMIZEも種が、TIME関数と同一と、いうこ... 返事を書く ノートメニュー
白石 和夫 <fbdfvqwhki> 2007/06/12 18:16:23
MyTimeは拡張精度なので,それが差がでる原因かも知れません。
function roundext(x:extended):extended;assembler;
asm
fld x
frndint
end;
function MyTime:extended;
var
t:double;
begin
t:=time;
t:=t-INT(t);
result:=RoundExt(t*8640000)/100.;
end;

   │ │   └先生のリストで、同値のMytimeに挟まれるMy... SECOND 2007/06/12 22:06:23  (修正5回) ツリーへ

Re: MyTimeは拡張精度なので,それが差がでる原... 返事を書く ノートメニュー
SECOND <cszcthjjdj> 2007/06/12 22:06:23 ** この記事は5回修正されてます
先生のリストで、同値のMytime に挟まれるMytime の揺らぎについて、考えてみました。
frndint コントロール・ワード、RC ビットが、変化しているとしか、思えません。
こんなものが、勝手に動いたりするものでしょうか。
バグが、このビットへ、時刻などを、書き込んでいれば、荒田氏の調査結果のように
なるかも、知れませんが・・・


自分で読めなかったので、勝手に注釈などを、
書き込んでしまいました。ご容赦下さい。

function roundext(x:extended):extended;
  assembler;
  asm
    fld x  // xを、コプロセッサーへ置数。
    frndint // 整数へ丸め(コントロール・ワード RC(bit 11~10)による。 00:近似値へ 01:−∞方向へ 10:+∞方向へ 11: 0方向へ)
  end;

function Mytime:extended;
  var
  t:double;
  begin
    t:=time;           // day 単位の実数
    t:=t-INT(t);           // day 単位の実数の小数部
    result:=RoundExt(t*8640000)/100.; // 0.01 秒単位の実数→ 整数へ丸め→ 秒単位の実数(小数下2桁止め)
  end

//RANDOMIZEの実体は

procedure MyRandmize;
  var
  x:extended;
  begin
    seed:=INT(mytime*100)+1;
    x:=random;
  end;

//となっています。
//Mytimeはtime関数の実体です。

   │ │    └整数丸めコントロール・ワードが勝手にゆら... 白石 和夫 2007/06/13 07:23:02  (修正2回) ツリーへ

Re: 先生のリストで、同値のMytimeに挟まれるMy... 返事を書く ノートメニュー
白石 和夫 <fbdfvqwhki> 2007/06/13 07:23:02 ** この記事は2回修正されてます
整数丸めコントロール・ワードが勝手にゆらぐことはありません。
正確に検証したわけではありませんが,おそらく,拡張精度と倍精度の仮数部ビット数の違いです。 2進モードのとき,Mytimeは倍精度に丸められてTIME関数の値になります。このとき,微妙な差が生じることがありえます。

   │ │     └私のパソコンでも荒田氏と同様の時刻の規則... SECOND 2007/06/13 07:53:00  (修正2回) ツリーへ

Re: 整数丸めコントロール・ワードが勝手にゆら... 返事を書く ノートメニュー
SECOND <cszcthjjdj> 2007/06/13 07:53:00 ** この記事は2回修正されてます
私のパソコンでも荒田氏と同様の時刻の規則性が
現れています。環境は、V599 と Win98SE です。
30秒ほど、違いますが、概ね、バイナリーシフトな
感じで、間隔が、広がって行きます。

   │ └DELETED  SECOND  2007/06/12 17:23:39  (削除) ツリーへ

Re: RANDOMIZE文がPCの内部時計を参照し種を与え... 返事を書く
SECOND <cszcthjjdj> 2007/06/12 17:23:39 ** この記事は削除されました

   └リストの中で、"田"が"川"になっていた事を... SECOND 2007/06/18 06:52:15  ツリーへ

Re: 十進BASICの組込み関数RNDにより発生する乱... 返事を書く ノートメニュー
SECOND <cszcthjjdj> 2007/06/18 06:52:15
リストの中で、"田"が"川"になっていた事をお詫びします。


インデックスへ EXIT
新規発言を反映させるにはブラウザの更新ボタンを押してください。