最近我一直在研究随机数,通常只使用Math.Random,因为我不需要使用更安全的方法,但是我认为学习这样的东西会很有用,想知道此功能的安全性/实用性以及我可以实现的一些改进。
function random_number(max) {
let buffer=new ArrayBuffer(8);
let ints=new Int8Array(buffer);
window.crypto.getRandomValues(ints);
ints[7]=64-1;
ints[6]|=0xf0;
let float=new DataView(buffer).getFloat64(0,true)-1;
return Math.floor(float*Math.floor(max+1));
}
答案 0 :(得分:0)
不,不是。
您正在有效地执行操作(通过将二进制数据转换为浮点值)正在计算floor(max * rand() / (RAND_MAX + 1.0))
(其中RAND_MAX
等于2 52 −1) 。除非max
是RAND_MAX+1
,as explained here的因数,否则这总是会导致分布失真。
这很容易证明:
function random_number(max) {
let buffer=new ArrayBuffer(8);
let ints=new Int8Array(buffer);
window.crypto.getRandomValues(ints);
ints[7]=64-1;
ints[6]|=0xf0;
let float=new DataView(buffer).getFloat64(0,true)-1;
return Math.floor(float*Math.floor(max+1));
}
function check_skew() {
var m = Math.floor(Math.pow(2,52) * 2 / 3);
var o = [0,0];
var ns = 100000;
for (i=0; i<ns; i++) o[random_number(m)&1]++; o;
console.log("Out of "+ns+" random numbers, "+o[0]*100/ns+
"% were even and "+o[1]*100/ns+"% were odd.");
}
<button onclick="check_skew()">Click this button a few times and check the results</button>
获取指定范围内的随机整数的正确方法是从一个统一的随机数开始,该随机数的位长至少应与max
的位长一样长。丢弃高位,如果结果小于或等于max
,则返回结果。否则,请重复该过程。
也许是这样的
function rand_int(max) {
// Returns a uniform random integer from 0 to max (inclusive)
var mask = 1;
var crypto = window.crypto;
max = Math.floor(max);
if (!crypto) throw "window.crypto undefined";
if (max < 1) throw "max value too small";
if (max > 0xffffffff) throw "max value too large";
// Generate binary mask (all 1)
while (mask < max) mask = (mask << 1) | 1;
// Now generate random values until one is within range
var r = new Int32Array(1);
do {
crypto.getRandomValues(r);
r[0] &= mask;
} while (r[0] > max);
return r[0];
}