前提
ここに質問の内容を詳しく書いてください。
乱数の一桁目がどうしても1に偏ってしまいます。
実現したいこと
1に偏らない乱数生成
発生している問題・エラーメッセージ
0.1900724777
0.2039962463
0.775511266
0.979726846
0.1416527678
0.114035211
0.1056855869
0.1825813151
0.1895523205
0.652536334
### 該当のソースコード ```JavaScript function random(){} random.prototype.initRandom = function(s) { this._s = new Array(123456789, 362436069, 521288629, 88675123); for(let i = 0; i < 4; i++) this._s[i] = s = 1812433253 * (s ^ (s >> 30)) + i; }; random.prototype.XorShift = function() { let s = this._s; let t = (s[0] ^ (s[0] << 11)); s[0] = s[1]; s[1] = s[2]; s[2] = s[3]; return (s[3] = (s[3] ^ (s[3] >> 19)) ^ (t ^ (t > 8))); }; random.prototype.seed = function(s) { let int = 0; s = String(s); for(i = 0; i < s.length; i++) { if(i == 0){ int += s.charCodeAt(i); } else { int += s.charCodeAt(i) * 31 ** i; } } if(int > 2 ** 31) { let max = Math.floor(int / 2 ** 31);//2 ^ 31の数 let min = int - max;// int = max + min; } this.initRandom(s); int = Math.abs(this.XorShift()); int = parseFloat("0." + int); return int; }; for(j = 0; j < 10; j++) console.log(new random().seed(j));
蛇足ですが、
このXorShiftは、C言語などからjavascriptへ移植したのでしょうか?
C言語だと恐らく整数32bit乗算ですが、式をそのままだと、javscriptのdouble相当の乗算になるので
そのまま式をもってきても結果が異なる為、同じシードで初期化してもC言語とjavascirptて異なる結果になります。具体的にはinitRandomの関数の中の、1812433253の数値との乗算で影響。
ほかの影響は、doblue乗算では、下位ビットの情報が失われるので、異なるシードでも同じ疑似乱数がでて来る確率がC言語の時より高くなります。
今回の場合、シード1234567890と同じ疑似乱数のシード 57830248,162653227,236482692,341305671,372299185,415135136,・・まだまだありました。
結構多い?
C言語のページから移植したものです。どのようなシードを使うのが正解でしょうか
正しく式を移植ができていないということです。
C言語の32bitの整数同士の乗算は、32bit x 32bit = 64 bitの内下位32bitになりますが
32bit同士の乗算をdoubleで計算すると 32bit相当 x 32bit相当 =52bit の後に下位32bit相当を取得しても、すでに失われた情報は取得できません。
例 javascriptは変数は、通常double相当
123456789*123456789を計算すると15241578750190521ではなく15241578750190520なってしまいます。このあと |0をしても32bitの値は、int同士の乗算と下位32bit同じ値にはなりません。
対処方法の1つは、整数32bit x 32bitを 32bit x下位16bitと32bit x 上位16bitで計算して後で必要な分を加算して取得します。
小学生で習った二桁同士の掛け算を1の位と10の位で別々に計算して加算するのと同じです。
javascriptって、BigIntってあるのですね。これで何でもなんとかなるかも、まだ使ったことないですが・・
返答ありがとうございます
回答3件