使用Math.random获取相同值的概率

时间:2015-01-28 17:55:10

标签: javascript random probability entropy

要求是在用户单击“提交”按钮时向数据库发送唯一ID。所以我使用的是Javascript Math.random方法。我只是想知道使用Math.random得到相同数字和比特大小的机会或可能性是什么。

5 个答案:

答案 0 :(得分:11)

你反对生日问题:即使有366个可能的生日,当你在一个房间里只有26个人时,一对生日相同的机会优于50-50 。通常,当您的数字接近样本大小的平方根时,可能会发生碰撞(26位于366的平方根附近)。

Javascript的Math.random()有大约52位的随机性。因此,当你的记录数接近2 ** 26(大约是6千万,这是一个相当适中的数据库大小)时,可能会发生冲突。

您应该使用至少128位,最好是256位的加密安全PRNG,以避免冲突。可能有现成的UUID库。

对于给定数量的键 k 和键空间 N ,碰撞的大概几率为:

1 - exp(( - k *(k-1))/(2 * N))

因此,对于k = 100万条记录,N = 2 ** 52,如果我做了正确的数学计算,则在9000中大约为1。这进一步假设Javascript的Math.random()真正使用了可用的填充52位随机性......这也是我不会做出的假设。

答案 1 :(得分:3)

不要这样做。信任(多个)客户提出独特的价值是行不通的。

即使每个客户端都保证生成唯一值,您也可以让两个客户端生成相同的值。由于大多数伪随机数生成器都以当前时间播种,因此当您获得更多用户时,这种情况就更有可能。

如果您正在创建数据库记录,那么您的数据库应该提供这样的功能。大多数或所有SQL数据库都有自动增量概念,许多NoSQL数据库都有一个等价物(Mongo肯定会用于ID)。允许数据库处理这个问题对性能有好处(它可以设置索引并分配空间来很好地处理ID),并且数据库对数据有最终决定权,因此它可以保证ID是唯一的。

如果失败了,您可以让服务器端生成一些唯一标识符(如UUID)并使用它。让服务器执行此操作并使用已知良好的算法(如类型4 UUID)可确保充分的随机性,从而不会发生冲突。请注意,除非您的数据库具有类型,否则使用UUID将具有与顺序ID非常不同的索引性能。

答案 2 :(得分:0)

如果您承诺使用客户端哈希函数,请使用crypto.getRandomValues()

这是一个示例实现:

const randomHash = function () {

    let array = new Uint32Array(1);
    let hash = window.crypto.getRandomValues(array);

    if (myExistingIds.includes(hash[0])) {
        randomHash();
    } else {
        myExistingIds.push(hash[0]);
    }
}

此函数将递归地拒绝生成的哈希,直到找到ID集合中尚未存在的哈希为止,该哈希仅需要进行几次迭代-很有可能只有一次迭代。

答案 3 :(得分:-2)

我更喜欢使用时间戳,客户端或用户相关标识符生成的随机数。

答案 4 :(得分:-2)

在我的浏览器(某些版本的Chrome)中,每个Math.random调用都会返回一个小数,精度为17小数。

这意味着两个Math.random值相同的可能性是

((1/10)(1/10))^17

0.0000000000000000000000000000000001(34个零)。

但是,这是一个特定于客户端的功能。

如果有人愿意,他们可以将功能更改为每次返回相同的值,或者他们想要的任何内容,因此我不会使用Math.random将唯一ID传递给数据库。

相反,我建议查看this stackoverflow question,这个UUID generating jsFiddle或创建自己的随机数生成器服务器端并传递JavaScript种子,或保证随机性和安全性的东西。