【问题标题】:Timestamp with Random Number in JSJS中带有随机数的时间戳
【发布时间】:2018-01-19 18:49:35
【问题描述】:

这是我之前提出的问题Is this JS Unique ID Generator Unreliable? (Getting collisions) 的后续问题。

在下面的脚本中,我使用 2 种方法生成 10000 个随机数。方法 1 是高达 10^6 的直接随机数,而方法 2 将高达 10^6 的随机数(与 [1] 中的想法相同)与当前的 JS Date().time() 时间戳连接。还有一种方法 [3],它只对 RNG 进行 Math.round,而不是整个连接结果。

我的问题是,如果您继续单击测试按钮,您会看到 [1] 总是产生 10000 个唯一数字,但 [2] 无论如何都会产生 ~9500 个。 [3] 产生 ~9900 但也不是最大值。这是为什么?从 [0..10^6] 中的前一个随机数获得 +/-1 并将其与时间戳连接的完全相反 +/-1 的时间戳混合的机会是不可能的。我们在一个循环中几乎在同一毫秒内生成。 10^6 是一个巨大的限制,比我原来的问题要大得多,我们知道这是真的,因为方法 [1] 非常有效。

是否存在某种截断,它会修剪字符串并使其更有可能出现重复?矛盾的是,较小的字符串比使用相同 RNG 的较大字符串效果更好。但如果没有截断,我希望结果是 100%,如 [1]。

function run() {
var nums1 = new Set(), nums2 = new Set(), nums3 = new Set();

for (var i = 0; i < 10000; i++) {
   nums1.add(random10to6th());
}
for (var i = 0; i < 10000; i++) {
   nums2.add(random10to6th_concatToTimestamp());
}
for (var i = 0; i < 10000; i++) {
   nums3.add(random10to6th_concatToTimestamp_roundRNGOnly());
}
console.clear();
console.log('Random 10^6 Unique set: ' + nums1.size);
console.log('Random 10^6 and Concat to Date().time() Unique set: ' + nums2.size);
console.log('Random 10^6 and Concat to Date().time(), Round RNG Only Unique set: ' + nums3.size);

function random10to6th() {
   return Math.random() * Math.pow(10, 6);
}

function random10to6th_concatToTimestamp() {
   return Math.round(new Date().getTime() + '' + (Math.random() * Math.pow(10, 6)));
}
}

function random10to6th_concatToTimestamp_roundRNGOnly() {
   return new Date().getTime() + '' + Math.round(Math.random() * Math.pow(10, 6));
}
<button onclick="run()">Run Algorithms</button>  
<p>(Keep clicking this button)</p>

【问题讨论】:

  • 您可以将数字作为字符串存储为数组的最大值.length 上的数千个(三个元素的组),请参阅How do I add 1 to a big integer represented as a string in JavaScript?
  • random10to6th_concatToTimestamp_roundRNGOnly() 返回不受精度问题影响的字符串而不是数字。
  • @le_m Math.round(Math.random() * Math.pow(10, 6)) 不影响精度问题?
  • Math.round(Math.random() * Math.pow(10, 6))Math.random() * Math.pow(10, 6) 更容易发生冲突,因为四舍五入将可能的值集限制为 10^6 个可能值。
  • 如果担心随机值的冲突,您可以在结果字符串中包含字母字符;例如,您可以创建和撤销Blob URLs N 次。另见How would one generate a MAC address in Javascript?

标签: javascript random


【解决方案1】:

是否存在某种截断,它会修剪字符串 并使其更有可能得到重复?

是的,只需对随机数进行四舍五入,即可截断小数位数。与非四舍五入的随机数相比,这减少了可能结果的数量。

除此之外,您还可以将时间戳(13 位)与 0 到 1000000(1 到 7 位)之间的值连接起来。因此,您的连接结果的总数将为 14 到 20 位,但 JavaScript 的 number 数据类型的精度有限,并且仅忠实地表示最多约 16 位的整数(请参阅Number.MAX_SAFE_INTEGER)。

示例:假设时间戳为1516388144210,您将随机数从500000 附加到500400

+'1516388144210500000' == 1516388144210500000
+'1516388144210500100' == 1516388144210500000
+'1516388144210500200' == 1516388144210500000
+'1516388144210500300' == 1516388144210500400
+'1516388144210500400' == 1516388144210500400

您可以看到,在将这些字符串转换为数字时,它们会被四舍五入为最接近的可用 IEEE-754 双精度(64 位)数字。这是因为1516388144210500000 &gt; Number.MAX_SAFE_INTEGER

【讨论】:

  • 但问题是,我正在连接成一个字符串,对吧?我在做+ '' + 所以我不再处理数字了。
  • 嗯,不,至少你的第二个函数——有问题的那个函数——返回Math.round(...),它将参数转换为数字。
  • 知道了。我后来添加了第三个,它是基于字符串的。但那也不是 100%。
  • 是的,因为你对随机数进行四舍五入,与非四舍五入的随机数相比,这实际上是对许多随机数字的截断(第一个函数)。
【解决方案2】:

我认为这里存在许多问题。我不知道以下每一项对观察到的差异有哪些影响或在多大程度上造成了差异,只是它们可以解释结果。

一个是因为您将一个数字与一个带有数字的字符串连接起来,然后将值强制回一个数字作为舍入结果的一部分。将意外结果输入到 Round 函数中是很容易的(这本身可能会由于浮动精度而导致冲突,如下所述)

其次,我认为当您连接时间戳时,您实际上 减少了结果数字的随机性。该函数很可能每秒被调用很多次;如果以速率 > Date.getTime() 精度调用它,则返回的值将与前一个循环迭代中生成的值相同。

第三,除非我错过了什么,你有没有考虑过随机数 gen 只能保证是 pseudo-random?在处理您发布的代码中的大值时,精度和数字限制会发挥作用。由于数字的最随机部分被附加到最不重要的部分,因此它更有可能被截断、截断或修改。

尝试反转您的串联并查看结果(只有大约 4 次左右的碰撞)。这些冲突是由我和@le_m 的答案概述的原因造成的。

function run() {
var nums1 = new Set(), nums2 = new Set()

for (var i = 0; i < 10000; i++) {
   nums1.add(random10to6th());
}
for (var i = 0; i < 10000; i++) {
   nums2.add(random10to6th_concatToTimestamp());
}
console.clear();
console.log('Random 10^6 Unique set: ' + nums1.size);
console.log('Random 10^6 and Concat to Date().time() Unique set: ' + nums2.size);

function random10to6th() {
   return Math.random() * Math.pow(10, 6);
}

function random10to6th_concatToTimestamp() {
   return Math.round((Math.random() * Math.pow(10, 6)) + '' + new Date().getTime());
}
}
<button onclick="run()">Run Algorithms</button>  
<p>(Keep clicking this button)</p>

【讨论】:

    猜你喜欢
    • 2015-04-20
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多