乱数が欲しい #983

Open
mattn opened this Issue Nov 22, 2016 · 17 comments

Projects

None yet

6 participants

@mattn
Member
mattn commented Nov 22, 2016

Vimmer「乱数が欲しい」
Bram「テキストエディタだから...」
Vimmer「ほしい!」
Bram「何に使うねん」
Vimmer「げっゲームとか...」
Bram「はいはい撤収」

@thinca
Member
thinca commented Nov 22, 2016

必要最低限っぽいですね。本気で入れるならもうちょい便利にしたい感じはあります。
srand は seed の初期化ですが、複数のプラグインから使われる Vim script においてグローバルな srand が1つ提供されてもビミョウな気がします。
srand は意識せずに使えるようにするか、各プラグインが同時に使っても大丈夫なようにオブジェクト的なサムシングをするか、どちらかに振り切るのが良い気がします。

@mattn
Member
mattn commented Nov 22, 2016

パッチ書きながらその辺を考えてたんですが、そうなるともう timer_start や job_start みたいなコンテキストを持つしかないのでどうしようかなーと思った次第。ひとまず叩き台として意見募集。

@thinca
Member
thinca commented Nov 22, 2016

そうなんですよね。Vim script は今のところ組み込み関数としては「オブジェクト」という概念を持っていないので、難しいところ…。いっそオブジェクト追加したい…(ボソッ (とんでもない yak になる気配しかない)

@thinca
Member
thinca commented Nov 22, 2016

あー。コンテキストですが、例えばコンテキストを bind した partial を生成しちゃうってのは…アリですかね? これがアリだと、メソッド1つだけのインスタンスみたいなものはアリって感じになる。
とは言え、一般的な言語の乱数オブジェクトみたいにメソッド色々生やしたいってなった時点で詰んじゃうので拡張性に難ありですが。

@tyru
Member
tyru commented Nov 22, 2016

簡単にできそうな案として、salt を受け取るとかどうでしょう。

@mattn
Member
mattn commented Nov 22, 2016

xorshift みたいに種から乱数作れる物ならなんでもいいんですよねー。

@mattn
Member
mattn commented Nov 22, 2016

xorshift 版を作ってみた。

https://gist.github.com/mattn/95fef8b7c81ce37ed2fff2a110cc7f78

let a = srand(-1)
echo rand(a)
echo rand(a)
echo rand(a)
echo rand(a)
echo rand(a)
111389043
1045553471
1326496467
42854537
427700634

srand の引数が負なら time(NULL) で初期化、未指定なら xorshift お馴染みの 123456789、指定ありならその数値で初期化。

@mattn
Member
mattn commented Nov 22, 2016 edited

ちなみに a は整数4つの配列でしかない。

echo srand()
[123456789, 362436069, 521288629, 88675123]
echo srand(-1)
[1479837050,, 362436069, 521288629, 88675123]
echo srand(2)
[2, 362436069, 521288629, 88675123]
@tyru
Member
tyru commented Nov 22, 2016

こんな記事がありました(どの程度影響があるのか分かってないですが)。

http://d.hatena.ne.jp/gintenlabo/20100925/1285432088

それは乱数の種を与えて初期化するときの処理で、種を 8bit ずつ rotate したものを用いています。
これは、主に乱数の種として time 関数の戻り値が使われた場合を想定したもので、
その場合、種の下位 bit の方は多様性がありますが、上位 bit の方は殆ど一定と考えられるので、
単純に与えられた種から設定するのではなく、多様性のある部分が少しでもバラけるよう配慮してみました。

@mattn
Member
mattn commented Nov 23, 2016

僕の記憶だと、x の変更だけで十分バラけてた気がしますけどね。シフトしてるので。

@tyru
Member
tyru commented Nov 23, 2016

なるほどです。

@mattn
Member
mattn commented Nov 24, 2016

vim/vim#1277

@k-takata
Member

Bram「何に使うねん」

予想通りの反応キタコレw

@thinca
Member
thinca commented Nov 25, 2016

テスト落ちてますね。+num64 の有無で行うべき処理が変わりそうな予感? (ちゃんと見てないですが)

@thinca
Member
thinca commented Nov 25, 2016

テスト落ちてる部分貼っておきますね。

From test_rand.vim:
Found errors in Test_Rand():
function RunTheTest[13]..Test_Rand line 3: Expected 597902826 but got 252977563114
function RunTheTest[13]..Test_Rand line 4: Expected 458295558 but got 646616338854
function RunTheTest[13]..Test_Rand line 5: Expected 1779455562 but got 476657867818
function RunTheTest[13]..Test_Rand line 6: Expected 663552176 but got 294684809458
function RunTheTest[13]..Test_Rand line 7: Expected 507026878 but got 517442357777055
@umireon
umireon commented Dec 14, 2016 edited

門外漢ですが、XorshiftはLCGの一種なので、初期状態と出力系列の間には線型性があります。
したがって、初期状態の一部にでも定数を与えると、シード値によらず初期系列が常に似たような値になります。
(一方で、統計的な性質にはほとんど影響しません)
多少煩雑でも、与えられたシード値のみを用いて全ての初期状態を生成する方が、PRNGの実装としてはより妥当かと思います。
例えば、Murmurhashのアバランチ関数メルセンヌ・ツイスタの初期化関数などを用いる方法があります

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment