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


HSPTV!掲示板


未解決 解決 停止 削除要請

2013
0428
(´ω`)例えば1万桁の任意の乱数など。26解決


(´ω`)

リンク

2013/4/28(Sun) 15:51:17|NO.53672

HSPってか頭の体操っぽい質問になっちゃいますが、以下の内容につきまして
よろしければ色々とご助言ご叱咤などをいただけましたら。(u´ω`)

HSPのrnd関数では、最大32,767までの乱数を得られますよね。
それ以上の乱数を得るにあたって、例えば0〜999,999までの乱数を得る、ってのは
非常に簡単で、桁ごとに0〜9の乱数を作って最後に文字列としてマージすればいい。

ところが、例えば0〜999,997までの乱数を得ようと思うと、前述の方法では
得られません(そのまんまやると7の部分でおかしなことになる)。
ましてや、0〜817,595までの乱数を得ることはこの方法ではできませんよね。

rnd関数もあるんだし、なんかうまいぐあいにやれば1万桁の任意の乱数とかも
意外と簡単に作れそうに思うんですが、ええ方法が思い浮かびません。
且つ、例えばリアルタイム処理の最中でも使えるような(16ms以上かからない程度の)
速度で作り出すことはできないかなあ、と。
ググってみましたが、モンテナントカ法とか中間ホニャララ法とかわけのわかんない
式ばかりでさっぱりなのです。

こんくらい思いつけねーのかよバーカとか、この程度の方程式も出せねーのかとか、
いろいろご教示いただけると嬉しく思います。(;ω;)



この記事に返信する


晩御飯

リンク

2013/4/28(Sun) 16:42:39|NO.53673

>例えば0〜999,999までの乱数を得る、ってのは非常に簡単で、
>桁ごとに0〜9の乱数を作って最後に文字列としてマージすればいい
その値を817,596で割ったときの剰余は0〜817,595のうちのどれかになりますよね
という意味ではなさそうですね



KA

リンク

2013/4/28(Sun) 17:31:21|NO.53674

>>ところが、例えば0〜999,997までの乱数を得ようと思うと、前述の方法では
>>得られません(そのまんまやると7の部分でおかしなことになる)。

999の乱数と997の乱数を組み合わせる。じゃダメ。



字がキタナイ

リンク

2013/4/28(Sun) 18:14:19|NO.53675

内部的にはrnd自体、最大値が32767の乱数が発生しているが、
それを「指定された数−1」が最大値の乱数になるように計算して
いるのでは?

話を置き換えると、

1〜6まで目のさいころで、1〜3の乱数を発生させるとすると、
1か2がでたら1、3か4がでたら2、5か6がでたら3という
ふうにすればいいわけで、

計算は、出目を2で割って、小数点以下を切り上げで、
1〜6が、1〜3にできます。

1÷2=0.5 小数点以下切り上げで1
2÷2=1       〃     1
3÷2=1.5     〃     2
4÷2=2       〃     2
5÷2=2.5     〃     3
6÷2=3       〃     3
  
rndでは、0〜32767の乱数で同じようなことをやっている
かと・・・。

これ以上の説明は、計算に弱いせいか、自分でもよくわかんなく
なってきた・・・www

とにかく、内部的には0〜999,999の乱数が発生するのであれば、
それを0〜999,997までや、0〜817,595までになるように計算すれば
いいというわけです。



KA

リンク

2013/4/28(Sun) 18:59:14|NO.53676

>>999の乱数と997の乱数を組み合わせる。じゃダメ。
そうか、1998や1999が出てこないのか。

0〜999,997 -> 0〜799,999 にして桁入れ替え。

>>0〜817,595までの乱数を得ること
最上位から1桁単位で乱数を得る。
○最上位は0〜8の乱数
 最上位が8未満→以降の桁は0〜9までの乱数
 最上位が8→次の桁は0〜1の乱数

○その次の桁
 上記の規則で繰り返し。

1桁単位じゃなくても、4桁単位でも同じように出来るでしょう。



y.tack

リンク

2013/4/28(Sun) 19:33:47|NO.53677

・1万桁の演算
システム総合、多目的DLL
HSP3用多倍長整数演算プラグイン・RSAモジュール
http://hsp.tv/make/tool1.html

を使えばいいですね



y.tack

リンク

2013/4/28(Sun) 19:43:23|NO.53678

>その値を817,596で割ったときの剰余は0〜817,595のうちのどれかになりますよね
>という意味ではなさそうですね
割る元が817596*1.4くらいの大きさなら偏りそうですが
すごい大きい数を剰余すればあんまり偏らないと思います



トホホッティー

リンク

2013/4/28(Sun) 19:56:39|NO.53679

randomize -1

とかにすれば?



YSR

リンク

2013/4/29(Mon) 01:59:27|NO.53683

マジレスすると、HSPのrnd関数の性能だと、
そのまま多段に繋げても乱数としての質がお察しになってしまうぞ……
それでも良けりゃ、3段ぐらい(32768^3=2^45≒3.5x10^13だからこれぐらいで十分?)
繋げて剰余を求めりゃ良いんじゃね?



(´ω`)

リンク

2013/4/29(Mon) 16:49:01|NO.53688

なるほど……非常に勉強になります。
皆様、わたしの戯言におつきあいいただき、感謝しております。(*´ω`*)

皆様から教えていただいたことを元に、ためしにモジュールを作ってみますた。
つたない作りですが、動かした感じでは一応乱数を作れてるみたいだし、
速度もこんなもんかなあ、と。

#module #defcfunc hugernd str a max = a : keta = strlen(max) : res = "" ; 同じ桁数の乱数を作る repeat keta res += str(rnd(10)) loop dim h1, keta : dim h2, keta repeat keta h1(cnt) = int(strmid(max,cnt,1)) h2(cnt) = int(strmid(res,cnt,1)) loop while ; 最上位の桁を比較、生成数の方が指定数未満なら確定、それ以外は引き算 if h1(0) <= h2(0) { dim kk, keta repeat keta h2(cnt) -= h1(cnt) loop for i, keta-1, 0, -1 if h2(i) < 0 { h2(i) += 10 h2(i-1) -= 1 } next } else { _break } wend res = "" repeat keta res += str(h2(cnt)) loop return res #global randomize pos 0,0 : button "乱数発生", *makernd stop *makernd color 255,255,255:boxf color 0,0,0 pos 20, 40 mes "5 未満" mes hugernd("5") mes "50 未満" mes hugernd("50") mes "500 未満" mes hugernd("500") mes "50000 未満" mes hugernd("50000") mes "5000000 未満" mes hugernd("5000000") mes "500000000000000 未満" mes hugernd("500000000000000") mes "50000000000000000000000000000000000000000000000000000000000000 未満" mes hugernd("50000000000000000000000000000000000000000000000000000000000000") stop
しかし、ちゃんとした乱数なのか、とゆわれると、どうなんですかねエヘヘという。

いちおう、目的の乱数(っぽいもの)は出せるようになりましたので解決にしておきます。
引き続き、「きったねえソースだなあ」「もっとこう書けるだろ」みたいなご叱責が
ありましたらバンバンお願いいたします。(*´Д`*)



(´ω`)

リンク

2013/4/29(Mon) 16:57:25|NO.53689

あっ(u゚ω゚ )ダメじゃんこれ……

もうちょい工夫しないといかんですね……



y.tack

リンク

2013/4/29(Mon) 18:12:32|NO.53690

僕が書くとこんなかんじになりました

#include "longint.hsp" lint=LongInt(0) lint_b=LongInt(0) randomize repeat 10100 r=rnd(10) lint*=10 lint+=r loop sdim _4mb,30000 _4mb=str(lint) lint_b=longint("55500000000000000000000") lint\=lint_b _4mb+="\n"+str(lint) mesbox _4mb,600,400 stop



KA

リンク

2013/4/29(Mon) 18:24:12|NO.53691


;---------------------- ;指定数範囲の乱数 ;---------------------- A="83245621" ;乱数の範囲 B=strlen(A) ;桁数収得 dim C,B ;桁分解 repeat B ;文字を数字にする C(cnt)=int(strmid(A,cnt,1)) loop repeat 20 ;単に確認用 G="" F=0 repeat B ;最上位から各桁の数字を処理 E=9 ;基本は0〜9の乱数 if F=0 : E=C(cnt) ;フラフが立っていれば数字範囲 D=rnd(E+1) ;乱数発生 if F=0 { ;フラグが立っていない if (D!E) { ;数字と乱数が同じでは無い F=1 ;フラグを立てる } } G=G+D loop mes G loop stop



KA

リンク

2013/4/29(Mon) 18:29:59|NO.53692

>>数字と乱数が同じでは無い
と言う所は
指定数以下だから以降、0〜9の乱数で良いということです。



通りすがり

リンク

2013/4/29(Mon) 18:40:30|NO.53693

残念ながらKAさんの方法では均等に数値が出ません。
11等にしてみれば分かりますが、10,11の確率が異様に高くなります。
単に上位の桁から決定するだけではそうなってしまいます。

…なーんて書きましたが、実際の解決法は浮かんでないんですが。
longint以上の任意の桁数の乱数を出すのは中々厳しそうですね…



(´ω`)

リンク

2013/4/29(Mon) 19:16:04|NO.53694

ああん、お二人ともオレの1/3分以下のソース量で実装とか!(*´Д`*)


>y.tack さま

longintモジュール、めっちゃ強力ですね……(u゚ω゚ )
ていうか、多倍長整数ってのがいまいちピンと来なかったんで「64桁の整数とか?」などと
勝手に思ってました、ググったら無限桁(メモリの許す限り)の整数のことだったんですね。

モロ正解だったんや!素直にこれ使えばえかったんや!


>KA さま

こちらは標準命令だけでの実装ですが……そうか!最上位の桁から順に見て、ある桁の生成した
乱数が同じ桁の数未満であればもう数値がオーバーすることはあり得ないから、後は単純に0〜9の
乱数をつなげていけばいいと!

剰余出さなきゃいけないから何度も引き算して、とかアホなことやらんでえかったんや!


頭悪い人間の頭の体操モドキにおつきあいいただき、皆様ほんとに感謝いたします。
ほうれん草をモリモリ食べたら発想力つくかしら……(;ω;)



(´ω`)

リンク

2013/4/29(Mon) 19:27:44|NO.53695

あっ、通りすがり氏のおっしゃる通りの問題が……
そうか、桁ごとに乱数を作る方式だと、上位桁の数字が小さい場合にその部分での偏りが
大きくなっちゃうんですね……

もともとのオレの発想が、特定の条件でのみ通用するものでしかないのか……
(最大値999や99,999,999,999,999,999など)

longint使うしかないのかな……
なんか、何かにアレッと気付いたらできそうなんだけどな……(´・ω・`)



y.tack

リンク

2013/4/29(Mon) 20:00:30|NO.53696

rndが嫌ならrndf使うとか

#include "longint.hsp" #include "hspda.as" lint=LongInt(0) lint_b=LongInt(0) rndf_ini repeat 10100 rndf_geti r,10 lint*=10 lint+=r loop sdim _4mb,30000 _4mb=str(lint) lint_b=longint("55500000000000000000000") lint\=lint_b _4mb+="\n"+str(lint) mesbox _4mb,600,400 stop
確かMT法乱数をちょっと調べたことがあるんですけど
unsigned intを使っててHSPに移植はあきらめました
JAVAにはunsigned int を longで代用してHSPLetには移植しましたが
数字に強い方でしたらHSPに移植できるかもしれませんね
ただMT法でも、乱数を並べると途中から予測できるとか(TT)
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html



KA

リンク

2013/4/29(Mon) 20:02:04|NO.53697

>>残念ながらKAさんの方法では均等に数値が出ません

それは自分でも分かっています、なので「単に確認用」で最大
数を超えない手法を示しただけです。

ランダム関数をrepeat内で使うと問題が有る、と言う質問を過
去見たような気もします。

----------------------------------------------------

使う用途によっては、longintで素数の平方根(無理数)を作っ
て、適当な桁を取り出せば可能でしょう。取り出す桁位置を替
えれば乱数が得られます。(超越数でも良い)

この場合、使う無理数と取り出す桁位置はランダムではありま
せんが、出てくる数字列は乱数です。(暗号化にも使える)

ただし特定数以下となると、検索する手間が増えます。



y.tack

リンク

2013/4/29(Mon) 20:25:46|NO.53698

>>実数乱数を取得してp1で指定した変数に代入します。
>>実数乱数は、 0以上で 1未満の実数となるもので、 Mersenne Twister アルゴリズムにより生成されます。
rndfってMT法だったんですね。知らなかった...

頑張って移植しようとした僕は馬鹿みたい



晩御飯

リンク

2013/4/29(Mon) 20:43:31|NO.53699

MTってコストが大きいのにHSPでは標準なのか
知らなかった



y.tack

リンク

2013/4/29(Mon) 21:31:48|NO.53700

字がキタナイさんのレスを読んで思ったんですけど
例えば777までの乱数を求めたい時は999までの乱数を求めて
777以上だと求めなおすとかどうですか?
って123以上とかになるとめんどくさい訳ですが



トホホッティー

リンク

2013/4/29(Mon) 21:56:33|NO.53701

僕の前の解答は任意の乱数とあったので乱数制御しただけです。



check

リンク

2013/4/29(Mon) 23:27:44|NO.53704

いろいろと回答は出ているようだが、なぜそんな巨大な乱数をリアルタイムで取得したいんだ?



KA

リンク

2013/4/30(Tue) 01:37:20|NO.53707

>>なぜそんな巨大な乱数をリアルタイムで取得したいんだ

そう思ったけど、「困難に挑む少年のロマン」では無いかと思います。
そして「それを木の陰から、潤んだ瞳でそっと見つめる美少女」。
・・・違うな・・・
「自由奔放に振る舞う少女」と、
「いつも陰ながら後始末をし、遠くから見つめている幼馴染の美少年」。

いやー、青春ですよ青春。

・・・今はGW、少し壊れた私です・・・



(´ω`)

リンク

2013/4/30(Tue) 09:08:13|NO.53712

checkさまの的確なツッコミにKAさまの浪漫あるフォロー。
まことに恐縮です……(*´Д`*)

元々は、32767以上の数値の乱数を取りたいってだけだったのですが、
どうせなら任意の大きさの乱数が取れたら汎用できるんじゃないかしら、と。
それでこんな大変なことに。

色々とお騒がせいたしております。(´・ω・`)



YSR

リンク

2013/4/30(Tue) 09:32:14|NO.53714

結論:実数乱数生成後掛け算でおk。

#include "hspda.as" #module #defcfunc rand int n rndf_get@ n_ return int(n_*n) #global repeat 10 mes rand(50000) loop stop
>NO.53699
MTはまだ軽いほうじゃない?
(HSPでXorshift実装してもより遅いだけだろうけど)



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