看起来Math.random()生成范围为[0,1)的64位浮点数,而新的crypto.getRandomValues()API仅返回整数.使用此API在[0,1)中生成数字的理想方法是什么?
这似乎有效,但似乎不是最理想的:
ints = new Uint32Array(2)
window.crypto.getRandomValues(ints)
return ints[0] / 0xffffffff * ints[1] / 0xffffffff
Run Code Online (Sandbox Code Playgroud)
编辑:澄清一下,我试图产生比Math.random()更好的结果.根据我对浮点的理解,应该可以获得52位随机性的完全随机分数.(?)
编辑2:为了给出更多背景知识,我不是要尝试以密码方式安全做任何事情,但有很多关于Math.random()实施不当的轶事故事(例如http://devoluk.com/google-chrome -math-random-issue.html)所以如果有更好的选择,我想使用它.
请记住,浮点数只是一个尾数系数,乘以2加到指数:
floating_point_value = mantissa * (2 ^ exponent)
Run Code Online (Sandbox Code Playgroud)
使用Math.random,您生成具有32位随机尾数并始终具有指数的浮点-32,以便小数位移位到左侧32位,因此尾数从不具有小数点左侧的任何部分.
mantissa = 10011000111100111111101000110001 (some random 32-bit int)
mantissa * 2^-32 = 0.10011000111100111111101000110001
Run Code Online (Sandbox Code Playgroud)
尝试运行Math.random().toString(2)几次以验证是否是这种情况.
解决方案:您只需生成一个随机的32位尾数并乘以Math.pow(2,-32):
var arr = new Uint32Array(1);
crypto.getRandomValues(arr);
var result = arr[0] * Math.pow(2,-32);
// or just arr[0] * (0xffffffff + 1);
Run Code Online (Sandbox Code Playgroud)
请注意,浮点没有均匀分布(由于尾数精度不高,数字变得越大,可能的值越稀疏),使得它们不适合加密应用程序或其他需要非常强的随机数的域.为此,您应该使用提供给您的原始整数值crypto.getRandomValues().
编辑:
JavaScript中的尾数是52位,因此您可以获得52位随机性:
var arr = new Uint32Array(2);
crypto.getRandomValues(arr);
// keep all 32 bits of the the first, top 20 of the second for 52 random bits
var mantissa = (arr[0] * Math.pow(2,20)) + (arr[1] >>> 12)
// shift all 52 bits to the right of the decimal point
var result = mantissa * Math.pow(2,-52);
Run Code Online (Sandbox Code Playgroud)
总而言之,不,这不比你自己的解决方案短,但我认为这是你希望做的最好的.您必须生成52个随机位,这些位需要从32位块构建,然后需要将其向下移回到1以下.