【问题标题】:Efficiently storing a list of prime numbers有效地存储素数列表
【发布时间】:2011-02-06 12:49:18
【问题描述】:

This article 说:

每个素数都可以表示为 30k±130k±730k±1130k±13 一些k。 这意味着我们每个可以使用 8 位 三十个数字来存储所有 素数;一百万个素数可以是 压缩到 33,334 字节


“这意味着我们可以使用每 30 个数字中的 8 位来存储所有素数”

这个“每 30 个数字 8 位”将用于 k,对吗?但每个 k 值不一定只占用一位。不应该是八个k值吗?


“一百万个素数可以压缩到 33,334 字节”

我不确定这是怎么回事。

我们需要指出两件事:

  • k 的值(可以任意大)

  • STATE 来自八个州之一(-13,-11,-7,-1,1,7,11,13)

我并没有关注“33,334 字节”是如何得出的,但我可以说一件事:随着质数的值越来越大,我们将需要更多空间来存储该值k

如何,那么我们可以将其修复为“33,334 字节”吗?

【问题讨论】:

  • 应该是“除了2、3、5以外的所有素数都可以表示为...”?
  • @MatrixFrog:当然,但是你的“解压例程”只会在处理压缩数据之前输出这 3 个。
  • 最简洁的表示是英文短语“The first Million primes”。其中包含解压缩所需的所有信息。

标签: algorithm compression storage primes


【解决方案1】:

这篇文章有点误导:我们不能存储 100 万个素数,但我们可以存储 100 万以下的所有素数。

k 的值来自它在列表中的位置。对于这 8 种排列(-13,-11..,11,13)中的每一种,我们只需要 1 位

换句话说,我们将使用 8 位来存储 k=0,使用 8 位来存储 k=1,使用 8 位来存储 k=2,等等。通过让这些顺序跟随,我们不需要为每 8 位指定 k 的值 - 它只是前 8 位 + 1 的值。

由于 1,000,000 / 30 = 33,333 1/3,我们可以存储这 8 位序列中的 33,334 个来表示低于 100 万的值是质数,因为我们涵盖了 k 可以具有的所有值,而 30k-13 不超过一百万。

【讨论】:

    【解决方案2】:

    您不需要存储 k 的每个值。如果要存储 100 万以下的素数,请使用 33,334 字节 - 第一个字节对应 k=0,第二个字节对应 k=1,依此类推。然后,在每个字节中,使用 1 位表示“素数”或“复合数” " 用于 30k+1、30k+7 等。

    【讨论】:

      【解决方案3】:

      这是一个位掩码——30 个可能是素数的 8 个值中的每一个都有一个位,因此每 30 个数字有 8 个位。要将所有最高 10^6 的素数制成表格,因此需要 8*10^6/30 = 2666667 位 = 33334 字节。

      要解释为什么这是一个好方法,您需要查看明显的替代方案。

      更天真的方法就是使用位掩码。你需要一百万位,125000 字节。

      您还可以存储素数本身的值。最多 1000000,这些值适合 20 位,并且有 78498 个素数,所以这给出了令人失望的 1569960 位(196245 字节)。

      另一种方法——虽然对于查找素数不太有用——是存储每个素数和下一个素数之间的差异。在一百万以下,这适合 6 位(只要您记得此时素数都是奇数,因此您只需要存储偶数差,因此可以丢弃最低位),对于 470998 位 == 58874 字节. (你可以通过计算你必须跳多少 mod-30 插槽来减少一点。)

      现在,除了 30 = 2*3*5 之外,30 并没有什么特别之处,所以这个查找实际上是在您开始之后引导您通过 Eratosthanes 筛网模式的位掩码表示。您可以改为使用 2*3*5*7 = 210,然后您必须考虑 +- 1、11、13、17、19、23、29、31、37、41、43、47、53、 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 48 个值。如果您使用 7 个 30 块来执行此操作,则需要 7*8=56 位,所以这是一个轻微的改进,但呃……不值得麻烦。

      所以这是紧凑存储相当小的素数的更好技巧之一。

      (有趣的是,如果素数随机出现(但与实际出现的数字相同,最多出现 1000000),则存储在 1 到 10^6 之间的素数中的信息量约为 0.397 位/因此,在幼稚的信息论假设下,您可能会认为存储前一百万个素数的最佳方法是使用 1000000*0.397 位或 49609 字节。)

      【讨论】:

      • @Rex Kerr:感谢您的比较。这让事情变得更加清晰。不过有一件事:你是怎么找到~0.397 bits per number 的?
      • p(prime) ~= 0.0785 因为前 1M 个数字中有 78.5k 个素数。熵的公式为 H = sum(-p*log2(p));我们有 p(prime) 和 p(not prime)=1-p(prime)。插件:-0.0785*log2(0.0785) - 0.9215*log2(0.9215) = 0.288 + 0.109 = 0.397
      【解决方案4】:

      从另一个角度来看,前 23,163,298 个素数可以被认为是可压缩的。它是每个间隙

      我使用这个事实here,将素数缓存的内存占用减少了 8 倍,即我没有使用number(8 个字节),而是只缓存素数之间的间隙,每个素数只使用 1 个字节.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-05
        • 1970-01-01
        • 2014-01-29
        • 2012-02-01
        • 2017-01-28
        • 1970-01-01
        相关资源
        最近更新 更多