内存不足的内存管理:查找和跟踪随机函数返回值的重复项

Posted

技术标签:

【中文标题】内存不足的内存管理:查找和跟踪随机函数返回值的重复项【英文标题】:Memory management with low memory: finding and tracking duplicates of random function return values 【发布时间】:2011-05-17 00:52:37 【问题描述】:

假设我有一个函数,它接受 32 位整数,并返回随机的 32 位整数输出。

现在,我想看看这个函数将在从 0 到 2^32-1 的所有可能输入值上返回多少和哪些重复值。如果我有超过 4gigs 的免费 ram,我可以让这件事变得简单,但我没有超过 1gig 的 ram。

我尝试将计算值映射到磁盘上,使用 4gig 文件,其中一个字节表示它有多少重复,但我注意到以我的 HDD 速度估计的完成时间将是未来 25 天! (我不得不使用 SSD,以免损坏我的硬盘......)

所以,现在下一步是在 RAM 中计算这一切,并且根本不使用磁盘,但是当我想如何优雅地解决这个问题时,我跑了。我能想到的唯一方法是循环 (2^32)*(2^32) 次函数,但这显然比我的 HDD 方法还要慢。

我现在需要一些讨厌的想法来加快速度!

编辑: 该函数并不是真正的随机函数,而是类似于随机函数,但事实上您不需要了解函数的任何内容,这不是问题所在。我想用肉眼看到所有重复项,而不仅仅是一些数学猜测可能有多少。为什么我这样做?出于好奇:)

【问题讨论】:

当你说重复时,你的意思是你在寻找in(5) => 5的情况,还是in(5) => 10 && in(6) => 10的情况? “随机”是指“确定性”。 @aroth,重复我的意思是两个(或更多)给定数字的返回值将返回相同的“随机”数字。 @Nick,我想我的意思是“确定性”(它实际上并不是一个随机函数,但输出非常接近随机值) 【参考方案1】:

要检查 2^32 个可能的重复项,您只需要 4 吉比特,即 512MB,因为每个值只需要一个比特。零位的第一次命中将其设置为 1,并且在每次命中 1 位时,您就知道您有一个重复项,并且可以将其打印出来或做任何您想做的事情。

即你可以这样做:

int value = nextValue(...);
static int bits[] = new int[ 0x08000000 ]();

unsigned int idx = value >> 5, bit = 1 << ( value & 31 );
if( bits[ idx ] & bit )
   // duplicate
else
    bits[ idx ] |= bit;

回应您的 cmets

是的,如果没有太多不同的重复项,那么将重复项放入地图是一个好主意。如果每个第二个值恰好出现两次,这里最坏的情况是 2^31 个条目。如果映射变得太大而无法立即保存在内存中,您可以对其进行分区,即只允许特定范围内的值,即整个数字空间的四分之一。如果副本分布相当均匀,这将使地图只有整个地图大小的 1/4。您当然需要在每个季度运行该程序 4 次才能找到所有重复项。

要查找第一个重复项,您可以分两次运行它:在第一次执行中,您使用位图查找重复项并将它们放入地图中。在第二遍中,如果地图中已经有一个条目并且值尚不存在,则跳过位图并将值添加到地图中。

不,没有充分的理由将 int 用于 unsigned int 数组。你也可以使用 unsigned int ,这实际上更适合这里。

【讨论】:

是的 - 如果 OP 没有多达 2^32 位,那么明显的时间内存权衡比上面建议的要好。如果您有 1/K 位图的空间,则通过 2^32 的可能性循环 K 次,每次丢弃不在当前 K 个区域中的 1 个的输出值。 25 天听起来很长——是不是到处寻找。获得基于磁盘的优化解决方案的一种方法是按顺序写出 2^32 个值,然后使用现有的优化磁盘排序例程,然后按顺序读取。 hmm... 位图是个好主意,但如果有 3 次点击相同的值怎么办?也许不可能,但我也想知道......好吧,我想我无法得到所有东西,我试试这个方法,看看它得到了多少重复。 512megs 是完美的,因为它是我可以使用的最大值! @mcdowella,是的,我想过把它做成块的想法,但那是我撞墙的地方,我真的不知道它比循环所有 (2^32)*( 2^32)。在为此苦苦挣扎的同时,我学会了按排序顺序查找/读取/写入值,然后进行查找,使其速度提高了 50 倍(而且非常安静),但仍然不够快:/ 实际上,这个位图的东西在这里很完美:我决定将找到的重复项存储到 std::map 中(因为我敢打赌它们不会很多),如果我遇到同样的情况很多次,我只是增加 std::map 值,在这里我得到了任何数量的重复项的完整列表,而且我可以轻松跟踪它具有哪些输入值。 OH 等一下,不幸的是我会丢失重复的另一部分的第一条记录,所以我只会知道哪个是第二个(或第三个等)重复输入值。我想解决这个问题,有想法吗?【参考方案2】:

无法回答的问题:为什么?。你想达到什么目的?

这是某种蒙特卡洛实验吗?

如果没有,只需查看 (P)RNG 的实现算法,它就会准确地告诉您值的分布情况。

查看Boost.Random 以获得比您想象的更多的选择,它会有例如uniform_int&lt;&gt; 和变量生成器可以限制您的输出范围,同时仍然对跨输出域的值分布有明确的保证

【讨论】:

为什么:我只是好奇这个函数会有多少“碰撞”。我不知道蒙特卡洛是什么。关键不是要知道分布,而是要查看它将返回多少重复项。该函数也不是真正的随机函数,但输出与随机函数非常相似。 @Rookie:那就玩得开心吧。 “非常类似于随机函数”是一个有趣的概念 :)

以上是关于内存不足的内存管理:查找和跟踪随机函数返回值的重复项的主要内容,如果未能解决你的问题,请参考以下文章

带返回 char* 函数的内存管理

matlab安装时储存空间不足

Linux下的动态内存管理

当内存不足时,c ++分配器使应用程序崩溃[重复]

PHP 7.2.9 在随机时间内存不足

带指针的内存管理