Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 生成BigInt值的随机样本_Javascript_Algorithm_Random_Floating Accuracy_Bigint - Fatal编程技术网

Javascript 生成BigInt值的随机样本

Javascript 生成BigInt值的随机样本,javascript,algorithm,random,floating-accuracy,bigint,Javascript,Algorithm,Random,Floating Accuracy,Bigint,对于用JavaScript实现的游戏,我需要生成一个随机列表,其中n个唯一数字的范围为[0,n,其中n可能大于Number.MAX\u SAFE\u INTEGER。这带来了三个重要挑战: 内存成本无法启用,因为我们没有足够的RAM。这意味着我们不能使用改进的Fisher-Yates shuffle算法从一个由n个元素组成的数组中获取n个经过洗牌的值。JS数组仅限于32位索引,但在此之前我们的RAM早就用完了。 执行时间应尽可能接近On而不是On。我希望n相对较小

对于用JavaScript实现的游戏,我需要生成一个随机列表,其中n个唯一数字的范围为[0,n,其中n可能大于Number.MAX\u SAFE\u INTEGER。这带来了三个重要挑战:

内存成本无法启用,因为我们没有足够的RAM。这意味着我们不能使用改进的Fisher-Yates shuffle算法从一个由n个元素组成的数组中获取n个经过洗牌的值。JS数组仅限于32位索引,但在此之前我们的RAM早就用完了。 执行时间应尽可能接近On而不是On。我希望n相对较小<100。 大多数数学运算使用双精度浮点值,不能处理这么大的数字。 我在Kim Hung Li的水库采样算法L中找到了前两个挑战的解决方案。总而言之,该算法背后的思想是,我们洗牌前n个数字以形成一个初始水库,然后我们逐渐用从剩余范围中抽取的随机数覆盖其中一些。我们使用几何级数来确定挖掘每次迭代要跳过多少个数字

在以下代码中,假设sampleSize是一个数字,populationSize是一个BigInt:

// Creates an array initialized with [0n, 1n, ... BigInt(count-1)].
function bigRange (count) {
    const array = Array(count);
    for (let i = 0; i < count; i += 1) {
        array[i] = BigInt(i);
    }
    return array;
}

function bigSample (sampleSize, populationSize) {
    const reservoir = shuffle(bigRange(sampleSize));
    let record = BigInt(sampleSize);
    let weight = exp(log(random()) / sampleSize);

    while (true) {
        const skipCount = floor(log(random()) / log(1 - weight));
        record += BigInt(skipCount);

        if (record >= populationSize) {
            return reservoir;
        }

        reservoir[floor(random() * sampleSize)] = record;
        record += BigInt(1);
        weight *= exp(log(random()) / sampleSize);
    }
}
然而,由于浮点数的精度有限,这段代码不适用于任意大的数字。随着populationSize的增长,最终会使用浮点数的非有效位,我们不再具有均匀分布,然后我们进入不安全的整数区域,最后可能出现skipCount将成为无限。知道这一点,我想知道

该功能在哪一点变得不可靠? 我有没有办法改进这个算法来弥补JavaScript的局限性? 还有更好的选择吗? 请注意,我对概率的了解有限,在花了一周时间翻阅我几乎不懂的科学论文后,我写了这段代码。我确实有一种替代方法,但效率要低得多,需要将随机数生成与谜题生成逻辑相混合。

如果n相对较小,则另一种方法是e是存储JavaScript映射或普通JavaScript对象中已经生成的数字,其中键是数字,但请注意,映射和普通对象都会将这些键转换为字符串,因此在这种情况下,键应该与值相同。如果n远小于n,则存储每个新随机数方法的时间es恒定的时间复杂度,n个随机数中的n个在第一次尝试时都不同的概率接近1

我已经写了一节,展示了根据n和n的大小从n个项目中抽取n个样本。 但是,如果你试图从n个可能值的巨大空间中生成n个唯一的随机数,例如,100位数字,这些数字以某种方式识别某些东西,那么有几件事需要记住,我将在后面详细介绍。 如果n相对较小,另一种方法是存储JavaScript映射或普通JavaScript对象中已经生成的数字,其中键是数字,但请注意,映射和普通对象都会将这些键转换为字符串,因此在这种情况下,键应该与值相同。如果n大大小于n,则time存储每个新随机数的时间复杂度接近于常数,而n个随机数中的所有n个在第一次尝试时都不同的概率接近于1

我已经写了一节,展示了根据n和n的大小从n个项目中抽取n个样本。 但是,如果你试图从n个可能值的巨大空间中生成n个唯一的随机数,例如,100位数字,这些数字以某种方式识别某些东西,那么有几件事需要记住,我将在后面详细介绍。
您可以一点一点地生成值并将其添加到trie中。当您不生成第一个数字时,您可以使用trie分支中的可用空间计数来确定进入每个分支的概率。如果浮点操作是完美的,这将从均匀分布中得到唯一的数字,但我猜这些是正确的trie中高级别概率的不一致性不会产生显著差异,因此,这需要进一步调查。请注意,如果生成了一个大于N的数字,则只需重新开始生成过程。如果不生成不必要的位,则重新生成的概率将小于50%,且小于预期值额外的一代是一代。

您可以一点一点地生成值并将其添加到trie中。当您不生成第一个数字时,您可以使用trie分支中的可用空间计数来确定进入每个分支的概率。如果浮点操作uld是完美的,但我猜在未来的高水平上,这些概率不一致
trie不会产生重大影响,因此,这需要进一步调查。注意,若您生成了一个大于N的数字,那个么您只需重新开始生成过程。如果不生成不必要的位,则重新生成的概率将小于50%,并且额外生成的预期值为1。

我只是仔细检查了一下,Map和Set实际上允许任何值作为键,甚至是BigInt,我已经忘记了,因为WeakMap只允许对象。我可以调用一个伪随机BigInt生成器n次,只要生成一个我已经选择的数字就重试,这确实是一个选项,只要n/n很小。我可以验证这个比率,并在可行时切换算法。我会研究的。请看我问题的编辑,其中讨论了根据n和n的大小从n个项目中抽取n个样本的各种方法,以及使用唯一随机数时需要记住的事项。哇,这是一个非常有用的参考资料,谢谢。我将尝试使用Crypto API实现RNDINT,因为Math.random在ECMAScript标准中的定义过于松散。在此期间,我将保留这个问题,但我可能会将其标记为已接受的解决方案,并在我自己的答案中发布我的最终JS代码。我只是反复检查,Map和Set实际上允许任何值作为键,甚至是BigInt,我已经忘记了,因为WeakMap只允许对象。我可以调用一个伪随机BigInt生成器n次,只要生成一个我已经选择的数字就重试,这确实是一个选项,只要n/n很小。我可以验证这个比率,并在可行时切换算法。我会研究的。请看我问题的编辑,其中讨论了根据n和n的大小从n个项目中抽取n个样本的各种方法,以及使用唯一随机数时需要记住的事项。哇,这是一个非常有用的参考资料,谢谢。我将尝试使用Crypto API实现RNDINT,因为Math.random在ECMAScript标准中的定义过于松散。在此期间,我将保留此问题,但我可能会将其标记为已接受的解决方案,并在我自己的答案中发布我的最终JS代码。我确实在本周早些时候阅读了有关尝试的内容,这实际上是我最初的方法,但我找不到关于它们被用于随机生成的太多信息。如果你有任何推荐人,我可以咨询,我很感兴趣。我在问题中没有提到这一点,因为我也对一般答案感兴趣,但我实际上知道N=a**b,其中a和b是小整数,这意味着我可以尝试深度b,其中节点正好有一个子节点,从而完全避免了再生问题。我在本周早些时候读到了关于尝试的内容,这实际上是我最初的方法,但我找不到太多关于它们被用于随机生成的信息。如果你有任何推荐人,我可以咨询,我很感兴趣。我在问题中没有提到这一点,因为我也对一般答案感兴趣,但我实际上知道N=a**b,其中a和b是小整数,这意味着我可以尝试深度b,其中节点正好有一个子节点,从而完全避免再生问题。