Javascript JS中带有随机数的时间戳

Javascript JS中带有随机数的时间戳,javascript,random,Javascript,Random,这是我之前问的问题的后续问题 在下面的scriptlet中,我使用2种方法生成10000个随机数。方法1是一个最大为10^6的直随机数,而方法2将最大为10^6的随机数(与[1]中的想法相同)与当前的JS Date().time()时间戳连接起来。还有一种方法[3],它只对RNG执行Math.round,而不是整个串联结果 我的问题是,如果您一直单击“测试”按钮,您会看到[1]始终生成10000个唯一数字,但[2]无论如何都会生成~9500个。[3] 产量约9900,但也从未达到最大值。为什么呢

这是我之前问的问题的后续问题

在下面的scriptlet中,我使用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]所示

函数运行(){
var nums1=new Set(),nums2=new Set(),nums3=new Set();
对于(变量i=0;i<10000;i++){
nums1.add(random10to6th());
}
对于(变量i=0;i<10000;i++){
nums2.add(random10to6th_concatottimestamp());
}
对于(变量i=0;i<10000;i++){
nums3.add(random10到第6个concatottimestamp_roundRNGOnly());
}
console.clear();
console.log('随机10^6唯一集:'+nums1.size);
console.log('Random 10^6和Concat to Date().time()唯一集:'+nums2.size);
console.log('Random 10^6 and Concat to Date().time(),Round RNG Only Unique set:'+nums3.size);
函数random10to6th(){
返回Math.random()*Math.pow(10,6);
}
函数random10to6th_concatottimestamp(){
返回Math.round(new Date().getTime()++''+(Math.random()*Math.pow(10,6));
}
}
函数random10to6th_concatottimestamp_roundRNGOnly(){
返回新日期().getTime()+''+Math.round(Math.random()*Math.pow(10,6));
}
运行算法
(继续单击此按钮)

是否存在某种截断,从而修剪字符串 使它更容易复制

是的,只要把一个随机数四舍五入,就可以去掉小数。与非舍入随机数相比,这减少了可能结果的数量

除此之外,还可以将时间戳(13位)与0到1000000(1到7位)之间的值连接起来。因此,连接的结果的总数将为14到20位,但JavaScript的数字数据类型精度有限,只能忠实地表示16位左右的整数(请参阅)

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

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

您可以看到,当将这些字符串转换为数字时,它们会四舍五入到最接近的可用IEEE-754双精度(64位)数字。这是因为
1516388144210500000>Number.MAX\u SAFE\u INTEGER

我认为这里存在许多问题。我不知道下面的每个项目对观察到的差异有什么贡献,或者贡献到什么程度,只是它们可能解释了结果

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

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

第三,除非我遗漏了什么,你有没有考虑过随机数gen只能保证是伪随机的?在处理像您发布的代码中这样的大值时,精度和数字限制是一个因素。由于数字的随机est部分加在最不重要的部分上,因此更可能被截断、截断或修改

尝试反转连接并查看结果(只有大约4次碰撞)。这些碰撞是由我和勒姆的答案所概括的原因造成的

函数运行(){
var nums1=new Set(),nums2=new Set()
对于(变量i=0;i<10000;i++){
nums1.add(random10to6th());
}
对于(变量i=0;i<10000;i++){
nums2.add(random10to6th_concatottimestamp());
}
console.clear();
console.log('随机10^6唯一集:'+nums1.size);
console.log('Random 10^6和Concat to Date().time()唯一集:'+nums2.size);
函数random10to6th(){
返回Math.random()*Math.pow(10,6);
}
函数random10to6th_concatottimestamp(){
返回Math.round((Math.random()*Math.pow(10,6))+“”+newdate().getTime());
}
}
运行算法

(继续单击此按钮)

您可以将数字作为字符串存储为数千(由三个元素组成的组),最大值为数组的
.length
。请参见
random10to6th\u concatToTimestamp\u 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