使用 crypto.generateValues() 生成 0 到 1 的随机数 [英] Generating random numbers 0 to 1 with crypto.generateValues()

查看:71
本文介绍了使用 crypto.generateValues() 生成 0 到 1 的随机数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看起来 Math.random() 生成了一个 [0,1) 范围内的 64 位浮点数,而新的 crypto.getRandomValues() API 只返回整数.使用此 API 在 [0,1) 中生成数字的理想方法是什么?

It looks like Math.random() generates a 64-bit floating point number in the range [0,1) while the new crypto.getRandomValues() API only returns ints. What would be the ideal way to produce a number in [0,1) using this API?

这似乎有效,但似乎不太理想:

This seems to work but seems suboptimal:

ints = new Uint32Array(2)
window.crypto.getRandomValues(ints)
return ints[0] / 0xffffffff * ints[1] / 0xffffffff

澄清一下,我试图产生比 Math.random() 更好的结果.根据我对浮点数的理解,应该有可能获得 52 位随机性的完全随机分数.(?)

To clarify, I am trying to produce better results than Math.random(). From my understanding of floating point, it should be possible to get a fully random fraction for 52 bits of randomness. (?)

编辑 2:为了提供更多背景信息,我并没有尝试做任何加密安全的事情,但是有很多关于 Math.random() 实施不佳的轶事故事(例如 http://devoluk.com/google-chrome-math-random-issue.html) 所以哪里有更好的选择,我想使用它.

EDIT 2: To give a little more background, I'm not trying to do anything cryptographically secure but there are a lot of anecdotal stories about Math.random() being implemented poorly (e.g. http://devoluk.com/google-chrome-math-random-issue.html) so where a better alternative is available I'd like to use it.

推荐答案

记住浮点数只是一个尾数系数,乘以 2 得到一个指数:

Remember that floating point numbers are just a mantissa coefficient, multiplied by 2 raised to an exponent:

floating_point_value = mantissa * (2 ^ exponent)

使用 Math.random,您可以生成具有 32 位随机尾数并且总是具有 -32 指数的浮点,以便小数位向左移动 32 位,因此尾数永远不会在小数位左侧有任何部分.

With Math.random, you generate floating points that have a 32-bit random mantissa and always have an exponent of -32, so that the decimal place is bit shift to the left 32 places, so the mantissa never has any part to the left of the decimal place.

mantissa =         10011000111100111111101000110001 (some random 32-bit int)
mantissa * 2^-32 = 0.10011000111100111111101000110001

尝试运行几次 Math.random().toString(2) 以验证是否确实如此.

Try running Math.random().toString(2) a few times to verify that this is the case.

解决方案:您可以生成一个随机的 32 位尾数并将其乘以 Math.pow(2,-32):

Solution: you can just generate a random 32-bit mantissa and multiply it by 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);

注意,浮点数不具有均匀分布(由于尾数缺乏精确性,数字越大,可能的值越稀疏),使它们不适合加密应用程序或其他需要很强随机数的域.为此,您应该使用 crypto.getRandomValues() 提供给您的原始整数值.

Note that floating points do not have an even distribution (the possible values become sparser the larger the numbers become, due to a lack of precision in the mantissa), making them ill-suited for cryptographic applications or other domains which require very strong random numbers. For that, you should use the raw integer values provided to you by crypto.getRandomValues().

JavaScript 中的尾数是 52 位,因此您可以获得 52 位的随机性:

The mantissa in JavaScript is 52 bits, so you could get 52 bits of randomness:

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);

所以,总而言之,不,这并不比您自己的解决方案短,但我认为这是您希望做的最好的事情.您必须生成 52 个随机位,需要从 32 位块构建,然后需要将其向下移回 1 以下.

So, all in all, no, this isn't ant shorter than your own solution, but I think it's the best you can hope to do. You must generate 52 random bits, which needs to be built from 32-bit blocks, and then it need to be shifted back down to below 1.

这篇关于使用 crypto.generateValues() 生成 0 到 1 的随机数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆