HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0720
ハンマーカンマ―重複しない乱数を使用したif10未解決


ハンマーカンマ―

リンク

2020/7/20(Mon) 11:45:30|NO.91043

重複しない乱数を90発生させて、その数が45以下かどうかで
2つの条件に均等に分岐させたいのですが、どうしても重複した数字がでてきて
偏ってしまいます。

なんとか両方の条件が45ずつになるようにできませんでしょうか。

コードは以下になります。

randomize
dim value, 90

foreach value : value.cnt = cnt : loop

foreach value
i = rnd(length(value))
if i = cnt : continue
value.cnt = value.cnt ^ value.i
value.i = value.cnt ^ value.i
value.cnt = value.cnt ^ value.i


if value.cnt <=45 {
mes "A"
}
else {
mes "B"
}
loop


お手数ですが、よろしくお願い致します。



この記事に返信する


ソラ

リンク

2020/7/20(Mon) 13:44:11|NO.91044


randomize length_=90;乱数の長さ length_half=length_/2;乱数の長さの半分 dim value,length_ dim Rndarr,length_;乱数表 repeat length_ RndSheet.cnt=rnd(length_);適当に乱数を入れる。被りとかは気にしなくておk loop ;乱数表を小さい順にソート sortval RndSheet,0;p2 並び順 (0=小さい順/1=大きい順) repeat length_ sortget i,cnt;ソート元のインデックスを取得 value.i=cnt if i<length_half{;0~89の乱数を作成するので、条件は <= ではなく < にする mes "A":A+1 }else { mes "B":B+1 } loop title "A:"+A+" B:"+B+""
こういうことでしょうか?
ちなみに標準命令のrndって微妙に偏りあるのでrndf_getiとかのほうが精度は高かった気がします。
(今回の場合はあまり関係ありませんが)



あらや

リンク

2020/7/20(Mon) 19:12:03|NO.91047

>重複しない乱数を90
90に限らず重複しないランダムな数列で
よく使われる手法ですが

randomize; length_ = 90;乱数の長さ dim d_rnd, length_; // 重複しない乱数を格納する配列変数 // 一旦配列に0〜89までの数値を順番に入れる repeat length_ d_rnd(cnt) = cnt; loop // 配列に入れた数値をランダムな箇所と入れ替える repeat length_ idx = rnd(length_); // ランダムな箇所を決定する // 以下3行は2つの数を入れ替える処理 d_rnd(cnt) += d_rnd(idx); d_rnd(idx) = d_rnd(cnt) - d_rnd(idx); d_rnd(cnt) -= d_rnd(idx); loop

こうすると配列に0〜89までの数値が(理屈上では)ランダムに格納されることになります。

まあ、ソラさんの仰る通りrnd自体に偏りがあるので
配列の中身もデバッグウィンドウなんかで確認すると結構偏ってたりします。



MillkeyStars

リンク

2020/7/20(Mon) 20:24:07|NO.91048

これでいいのかな。

screen 0,1000,600,0 font "MSゴシック",12 randomize dim RndTable,90 dim value,90 //乱数テーブル作成 repeat 90 RndTable(cnt) = cnt value_check += RndTable(cnt) loop repeat 90 //value 0〜44 用 i = rnd(90 - cnt) value(cnt) = RndTable(i) //利用した乱数テーブル要素を後方に移動 tmp = RndTable(i) RndTable(i) = RndTable(89 - cnt) RndTable(89 - cnt) = tmp //以下表示用です(value 0〜44) までのデータのみの表示、画面に入らないので pycnt = cnt //表示用縦座標 if (cnt < 45){ pycnt = cnt pos 0,pycnt * 10 : mes strf("i:%02d / value:%02d / tmp:%02d",i,value(cnt),tmp) //交換済み乱数テーブル(0〜44要素まで)本来は 0〜89までだけど画面に... repeat 45 pos 150 + (cnt * 15),pycnt * 10 : mes strf("%02d",RndTable(cnt)) loop } loop value_full = 0 repeat 90 value_full += value(cnt) if (value(cnt) < 45){ a++ } else { b++ } loop pos 0,550 mes "a="+a+" / b="+b+" / "+value_full+" : "+value_check



MillkeyStars

リンク

2020/7/20(Mon) 20:29:32|NO.91049

追記です。分割した時のコメントを間違えたままです。
正確には //value 0〜44 用 は //value 0 〜 89用です。



ソラ

リンク

2020/7/21(Tue) 13:17:03|NO.91053

あらやさんのソースコードですが、idxとcntが同じ値になった時に0が重複してしまうので

if idx=cnt:continue
この一行を追加したほうがいいかと思います。



あらや

リンク

2020/7/21(Tue) 14:43:28|NO.91054

>ソラさん
たしかにそうでした
雑で申し訳ありません。

失礼いたしました。



Makoto

リンク

2020/7/21(Tue) 16:47:11|NO.91055

あらやさんとほとんど同じですが
シャッフルのアルゴリズムを使用したものです

randomize dim a,90 repeat 90 a(cnt) = cnt loop for i , 90 - 1, 0 , -1 j = rnd(i + 1) b = a(i) a(i) = a(j) a(j) = b next repeat 90 pos (cnt \ 10) * 20 , (cnt / 10) * 20 mes a(cnt) loop
参考
https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%83%E3%82%B7%E3%83%A3%E3%83%BC%E2%80%93%E3%82%A4%E3%82%A7%E3%83%BC%E3%83%84%E3%81%AE%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB



さか

リンク

2020/7/21(Tue) 22:10:43|NO.91061

面白そうなので自分も参加。
皆さんの回答のように0〜89までの数字をランダムにセット
したいということですよね。
単純に重複しない数が出るまで乱数取得を繰り返します。


randomize dim value, 90 ii = 0 repeat r = rnd( length( value ) ) repeat ii if value.cnt == r: r = -1: break loop if r == -1: continue value.ii = r ii ++: if ii = length( value ): break loop repeat length( value ) pos (cnt \ 10) * 20 , (cnt / 10) * 20 mes value.cnt loop stop



kanamaru

リンク

2020/7/21(Tue) 22:40:48|NO.91062

重複しなくなるまで繰り返すぐらいだったら
とりあえず全部に-1入れておいて
basyoをランダムに決めて-1だったら代入する方がいいと思います。
計測してないけど、昇順で代入してシャッフルする方が速いとは思うけど。

randomize dim value, 90 repeat 90 value(cnt)=-1 loop repeat 90 c=cnt repeat i=rnd(90) if(value(i)=-1){ value(i)=c break } loop loop repeat 90 mes value(cnt) loop



ソラ

リンク

2020/7/23(Thu) 14:15:26|NO.91064

暇だったので比較プログラムを作ってみました。
(各アルゴリズムの命名は適当につけました、見当違いだったらごめんなさい)
個人的には入れ替え型が一番早いかな、と思ったのですがソート型が一番早くてびっくりです。
計算量的にソートって無駄がありそうなんですが・・・

#uselib "winmm.dll" #cfunc global timeGetTime "timeGetTime" #const Ofx 300;1回あたりの時間を表示する位置 #const DrawOfy 160;乱数表を可視化した図形 screen 0,600,260 randomize 繰り返し回数=1000 posx=10:posy=10;表示用 line_=0 StartTime=timeGetTime() repeat 繰り返し回数 length_=90;乱数の長さ length_half=length_/2;乱数の長さの半分 dim value,length_ dim Rndarr,length_;乱数表 repeat length_ RndSheet.cnt=rnd(length_);適当に乱数を入れる。被りとかは気にしなくておk loop ;乱数表を小さい順にソート sortval RndSheet,0;p2 並び順 (0=小さい順/1=大きい順) repeat length_ sortget i,cnt;ソート元のインデックスを取得 value.i=cnt loop /* if length_>cnt{ repeat length_ color value.cnt,value.cnt,value.cnt:pset cnt,line_+DrawOfy loop line_+1 } //*/ loop EndTime=timeGetTime() color 0,0,0 pos posx,posy:mes "ソート型 (提案者:ソラ)" pos posx+Ofx,posy:mes "1回あたり"+(double(EndTime-StartTime)/limitf(繰り返し回数,1))+"ms" line_=0 StartTime=timeGetTime() repeat 繰り返し回数 length_ = 90;乱数の長さ dim value, length_; // 重複しない乱数を格納する配列変数 // 一旦配列に0〜89までの数値を順番に入れる repeat length_ value(cnt) = cnt; loop // 配列に入れた数値をランダムな箇所と入れ替える repeat length_ idx = rnd(length_); // ランダムな箇所を決定する if idx=cnt:continue // 以下3行は2つの数を入れ替える処理 value(cnt) += value(idx); value(idx) = value(cnt) - value(idx); value(cnt) -= value(idx); loop /* if length_>cnt{ repeat length_ color value.cnt,value.cnt,value.cnt:pset cnt+100,line_+DrawOfy loop line_+1 } //*/ loop EndTime=timeGetTime() posy+25 color 0,0,0 pos posx,posy:mes "入れ替え型(提案者:あらやさん) pos posx+Ofx,posy:mes "1回あたり"+(double(EndTime-StartTime)/limitf(繰り返し回数,1))+"ms" line_=0 StartTime=timeGetTime() repeat 繰り返し回数 dim RndTable,90 dim value,90 //乱数テーブル作成 repeat 90 RndTable(cnt) = cnt value_check += RndTable(cnt) loop repeat 90 //value 0〜44 用 i = rnd(90 - cnt) value(cnt) = RndTable(i) //利用した乱数テーブル要素を後方に移動 tmp = RndTable(i) RndTable(i) = RndTable(89 - cnt) RndTable(89 - cnt) = tmp loop /* if length_>cnt{ repeat length_ color value.cnt,value.cnt,value.cnt:pset cnt+200,line_+DrawOfy loop line_+1 } //*/ loop EndTime=timeGetTime() posy+25 color 0,0,0 pos posx,posy:mes "片付け型 (提案者:MillkeyStarsさん)" pos posx+Ofx,posy:mes "1回あたり"+(double(EndTime-StartTime)/limitf(繰り返し回数,1))+"ms" line_=0 StartTime=timeGetTime() repeat 繰り返し回数 dim value,90 repeat 90 value(cnt) = cnt loop for i , 90 - 1, 0 , -1 j = rnd(i + 1) b = value(i) value(i) = value(j) value(j) = b next /* if length_>cnt{ repeat length_ color value.cnt,value.cnt,value.cnt:pset cnt+300,line_+DrawOfy loop line_+1 } //*/ loop EndTime=timeGetTime() posy+25 color 0,0,0 pos posx,posy:mes "入れ替え型 (提案者:Makotoさん)" pos posx+Ofx,posy:mes "1回あたり"+(double(EndTime-StartTime)/limitf(繰り返し回数,1))+"ms" line_=0 StartTime=timeGetTime() repeat 繰り返し回数 dim value, 90 ii = 0 repeat r = rnd( length( value ) ) repeat ii if value.cnt == r: r = -1: break loop if r == -1: continue value.ii = r ii ++: if ii = length( value ): break loop /* if length_>cnt{ repeat length_ color value.cnt,value.cnt,value.cnt:pset cnt+400,line_+DrawOfy loop line_+1 } //*/ loop EndTime=timeGetTime() posy+25 color 0,0,0 pos posx,posy:mes "総当り型 (提案者:さかさん)" pos posx+Ofx,posy:mes "1回あたり"+(double(EndTime-StartTime)/limitf(繰り返し回数,1))+"ms" line_=0 StartTime=timeGetTime() repeat 繰り返し回数 dim value, 90 repeat 90 value(cnt)=-1 loop repeat 90 c=cnt repeat i=rnd(90) if(value(i)=-1){ value(i)=c break } loop loop /* if length_>cnt{ repeat length_ color value.cnt,value.cnt,value.cnt:pset cnt+500,line_+DrawOfy loop line_+1 } //*/ loop EndTime=timeGetTime() posy+25 color 0,0,0 pos posx,posy:mes "フラグ型 (提案者:kanamaruさん) pos posx+Ofx,posy:mes "1回あたり"+(double(EndTime-StartTime)/limitf(繰り返し回数,1))+"ms"



ONION software Copyright 1997-2023(c) All rights reserved.