【问题标题】:C# Prime Generator, Maxxing out Bit ArrayC# Prime 生成器,Maxxing 出位数组
【发布时间】:2010-11-01 17:07:32
【问题描述】:

(C#,素数生成器) 下面是一些我和朋友正在研究的代码:

public List<int> GetListToTop(int top)
{            
    top++;
    List<int> result = new List<int>();
    BitArray primes = new BitArray(top / 2);
    int root = (int)Math.Sqrt(top);
    for (int i = 3, count = 3; i <= root; i += 2, count++)
    {
        int n = i - count;
        if (!primes[n])
            for (int j = n + i; j < top / 2; j += i)
            {
                primes[j] = true;
            }
    }
    if (top >= 2)
        result.Add(2);            
    for (int i = 0, count = 3; i < primes.Length; i++, count++)
    {
        if (!primes[i])
        {
            int n = i + count;
            result.Add(n);
        }
    }

    return result;
}

在我笨拙的 AMD x64 1800+(双核)上,在 34546.875 毫秒内所有低于 10 亿的素数。问题似乎是在位数组中存储更多。试图增加超过 20 亿的数据比 bitarray 想要存储的要多。关于如何解决这个问题的任何想法?

【问题讨论】:

    标签: c# primes bitarray


    【解决方案1】:

    我会将阵列的一部分“交换”到磁盘上。我的意思是,将你的位数组分成五亿个位块并将它们存储在磁盘上。

    在任何时候都只有几个块在内存中。使用 C#(或任何其他 OO 语言),应该很容易将巨大的数组封装在这个分块类中。

    您会为此付出更慢的生成时间,但在我们获得更大的地址空间和 128 位编译器之前,我看不到任何解决办法。

    【讨论】:

    • 我们现在有 64 位编译器,不是吗?我知道我们在大型机世界中这样做。我原以为英特尔 C++ 编译器(至少)是 64 位的,因为他们已经推出这些芯片一段时间了。
    【解决方案2】:

    或者作为 Pax 建议的替代方法,利用 .NET 4.0 中新的 Memory-Mapped File 类,让操作系统决定在任何给定时间哪些块需要在内存中。

    但是请注意,您需要尝试优化算法以增加局部性,这样您就不会不必要地在内存中交换页面(比这句话听起来更棘手)。

    【讨论】:

      【解决方案3】:

      使用多个 BitArray 来增加最大大小。如果一个数字要大位移并将结果存储在位数组中以存储位 33-64。

      BitArray second = new BitArray(int.MaxValue);
      long num = 23958923589;
      if (num > int.MaxValue)
      {
          int shifted = (int)num >> 32;
          second[shifted] = true;
      }
      
      long request = 0902305023;
      if (request > int.MaxValue)
      {
          int shifted = (int)request >> 32;
          return second[shifted];
      }
      else return first[request];
      

      当然,如果 BitArray 支持最大为 System.Numerics.BigInteger 的大小,那就太好了。
      交换到磁盘会使您的代码非常慢。
      我有一个 64 位操作系统,而我的 BitArray 也仅限于 32 位。

      PS:你的素数计算看起来很奇怪,我的看起来像这样:

      for (int i = 2; i <= number; i++)
          if (primes[i])
              for (int scalar = i + i; scalar <= number; scalar += i)
              {
                  primes[scalar] = false;
                  yield return scalar;
              }
      

      【讨论】:

        【解决方案4】:

        Sieve 算法的性能会更好。我可以在不到 4 分钟的时间内确定 int 范围的所有 32 位素数(总共约 1.05 亿个)。当然,返回素数列表是另一回事,因为内存需求将略高于 400 MB(1 int = 4 字节)。使用 for 循环将数字打印到文件中,然后导入数据库以获得更多乐趣:) 但是对于 64 位素数,程序需要进行多次修改,并且可能需要在多个节点上分布式执行。也可以参考以下链接

        http://www.troubleshooters.com/codecorn/primenumbers/primenumbers.htm

        http://en.wikipedia.org/wiki/Prime-counting_function

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-02-25
          • 2016-03-05
          • 1970-01-01
          • 2012-02-05
          • 2018-02-11
          • 2023-03-29
          • 2013-10-01
          相关资源
          最近更新 更多