【问题标题】:Largest amount of entries in lua tablelua 表中的最大条目数
【发布时间】:2018-06-02 17:36:42
【问题描述】:

我正在尝试在 Lua 中构建 Sieve of Eratosthenes,我尝试了几件事,但我发现自己遇到了以下问题: Lua 的表对于这种情况来说太小了。如果我只想创建一个包含所有数字的表格(请参见下面的示例),那么即使只有数字的 1/8(...),表格也太“小”了(我承认这个数字很大)......

max = 600851475143
numbers = {}

for i=1, max do
    table.insert(numbers, i)
end

如果我在我的 Windows 机器上执行此脚本,则会出现一条错误消息:C:\Program Files (x86)\Lua\5.1\lua.exe: not enough memory。在我的 Linux 机器上运行 Lua 5.3 时,我也尝试过,错误只是 killed。所以很明显lua无法处理条目的数量。

我真的不知道是否不可能在 lua 表中存储这么多条目,或者有一个简单的解决方案(也尝试使用长字符串......)? Lua 表中最大的条目数量到底是多少?

更新:是否可以手动为表分配更多内存?

更新2(第二个问题的解决方案):第二个问题很简单,我只是通过运行每个数字直到程序中断来测试它:33.554.432 (2^25) 个条目适合我的 12 GB RAM 系统上的一个一维表。为什么是 2^25?因为每个数字 64 位 * 2^25 = 2147483648 位正好是 2 GB。这似乎是 Lua for Windows 32 位编译器的标准内存分配大小。

附:您可能已经注意到这个数字来自欧拉计划问题 3。是的,我正在努力实现这一点。请不要给出具体的提示(..)。谢谢你:)

【问题讨论】:

  • N Lua 值(甚至布尔值)组成的长数组在 Lua 中至少占用 16*N 字节的内存。
  • 就像我在我的回答和@Piglet 在他的回答中解释的那样,很可能有 ``` 64*N``` 位(:8 --> 16 字节)的内存被占用。问题是如何解决问题...
  • 你们俩都错了。 Lua 为数组的一个元素(128 位)花费 16 个字节。 Lua 太浪费了 :-)
  • @EgorSkriptunoff 你能告诉我如何更有效地执行此操作或如何手动为表分配内存吗?
  • 您应该找到另一种解决方案(使用较短的表格)。你要求不要给你提示:-)

标签: lua lua-table


【解决方案1】:

埃拉托色尼筛法只需要每个数字一位,表示该数字是否被标记为非质数。

减少内存使用的一种方法是使用按位数学来表示每个表条目中的多个位。当前的 Lua 实现对按位或 - 等具有内在支持。根据底层实现,您应该能够为每个表条目表示 32 位或 64 位(数字标志)。

另一种选择是使用一个或多个非常长的字符串而不是表格。您只需要一个线性数组,这实际上就是字符串。只需在每个位置都有一个带有“t”或“f”,或“0”或“1”的长字符串。

警告:Lua 中的字符串操作总是涉及重复,这会迅速变成 n² 或更复杂的性能。对于整个庞大的序列,您不希望有一个连续的字符串,但您可能会将其分解为一千块或 2 的某个幂的块。这会将您的内存使用量减少到每个数字 1 个字节,同时最大限度地减少开销。

编辑:在注意到其他地方提出的观点后,我意识到您的最大数量是如此之大,以至于即使每个数字有一点,您的内存需求最佳约为 73 GB strong>,这是非常不切实际的。我建议遵循 Piglet 在他们的回答中给出的建议,看看 Jon Sorenson 的筛子版本,它适用于空间的一部分而不是整个东西。

我会留下我的建议,因为它可能对 Sorenson 的筛子仍然有用,但是是的,你遇到的问题比你意识到的要大。

【讨论】:

  • 再次感谢,我会在接下来的几天尝试相应地调整我的算法。我会看看我将如何实现这整个事情:)
【解决方案2】:

Lua 使用双精度浮点数来表示数字。这是每个数字 64 位。 600851475143 个数字产生近 4.5 TB 的内存。

所以这不是 Lua 或其表的错。错误消息甚至说

内存不足

您只是没有足够的 RAM 来分配那么多。

如果您仔细阅读链接的维基百科文章,您会发现以下部分:

正如 Sorenson 所说,埃拉托色尼筛子的问题不是 它执行的操作数,而是它的内存 要求。[8] 对于较大的 n,素数范围可能不适合 记忆;更糟糕的是,即使对于中等的 n,它的缓存使用率也很高 次优。该算法遍历整个数组 A,展示 几乎没有参考地点。

分段筛可以解决这些问题,其中 一次只筛选范围的一部分。 [9]这些已经 自 1970 年代以来就为人所知,工作如下 ...

【讨论】:

  • 感谢您的回答。我读了那篇文章(这基本上就是我试图将数字分成 8 部分的原因)。 :) 我有 16 GB 的 RAM,所以这应该不是问题。但正如我在回答中所描述的:Lua 只使用其中的 2 个......
  • @creyD - 听起来您正在使用 Lua 的 32 位实现。你能切换到64位吗?如果您仅获得 32 位应用程序中隐含的 2GB 可寻址空间,则您不可能表示 600,851,475,143 个数字。那将是,每个数字至少 1 位,或 75,106,434,393 字节……那是 75 GB,比您拥有的多 73 字节。事实上,它比当今真正优秀的 PC 还要多 9 GB。您确定您真的要使用该最大数量吗?如果是这样,您将不得不想出一个可以向后清理的增量解决方案。
  • @creyD 事实上,这就是上面的 Piglet 在第二个块引用中所指的内容。
  • @Piglet - 检查您的 SI 前缀。包含 600851475143 双精度数字的原始数组需要 ~4.5 TiB,而不是 GiB。 :)
  • @AikenDrum 哦,是的,你是对的,我被计算器上的小数点弄糊涂了……我有英文窗口,但不知何故,我的计算器以德语表示法显示结果……感谢您指出.不知道 TiB 是什么 ;) GiB 看起来真棒,呵呵。
猜你喜欢
  • 1970-01-01
  • 2011-02-11
  • 2022-01-15
  • 2019-06-24
  • 2011-07-07
  • 2018-05-18
  • 2019-09-20
  • 1970-01-01
相关资源
最近更新 更多