生成质数的最优雅方法


84

什么是实现此功能的最佳方法:

ArrayList generatePrimes(int n)

此函数生成第一个n素数(edit:where n>1),因此generatePrimes(5)将返回ArrayListwith {2, 3, 5, 7, 11}。(我正在用C#进行此操作,但是我对Java实现很满意-或其他与此类似的语言(因此没有Haskell))。

我确实知道如何编写此函数,但是昨晚当我这样做时,它并没有达到我希望的那样好。这是我想出的:

ArrayList generatePrimes(int toGenerate)
{
    ArrayList primes = new ArrayList();
    primes.Add(2);
    primes.Add(3);
    while (primes.Count < toGenerate)
    {
        int nextPrime = (int)(primes[primes.Count - 1]) + 2;
        while (true)
        {
            bool isPrime = true;
            foreach (int n in primes)
            {
                if (nextPrime % n == 0)
                {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime)
            {
                break;
            }
            else
            {
                nextPrime += 2;
            }
        }
        primes.Add(nextPrime);
    }
    return primes;
}

尽管我不希望速度明显低效,但我不太担心速度。我不介意使用哪种方法(天真或筛子或其他任何方法),但我确实希望它相当短并且很明显如何工作。

编辑:感谢所有答复,尽管许多人没有回答我的实际问题。重申一下,我想要一段漂亮的干净代码来生成素数列表。我已经知道如何使用多种方法来实现它,但是我倾向于编写不太清晰的代码。在此线程中,提出了一些好的选择:

  • 我最初拥有的版本的更好版本(Peter Smit,jmservera和Rekreativc)
  • 一种非常干净的Eratosthenes(starblue)筛子的实现
  • 使用JavaBigIntegernextProbablePrime编写非常简单的代码,尽管我无法想象它特别有效(dfa)
  • 使用LINQ延迟生成素数列表(Maghis)
  • 在文本文件中放入很多素数,并在必要时读入(普通话)

编辑2:我已经在C#中实现了此处给出的几种方法,以及此处未提及的另一种方法。他们都有效地找到了前n个素数(而且我有一种体面的方法来确定要提供给筛子的极限值)。


12
不,这也不是欧拉计划的:-)
大卫·约翰斯通

1
最好是我退后ienumerable <int>并逐一产生
Felice Pollano 2012年

4
我想知道的是生成质数的最不优雅的方法是什么。我在考虑涉及Access数据库的问题吗?
j_random_hacker

1
为了对比,2008年的Haskell代码由BMephnubBy (((>1).).gcd) [2..]。它从2开始仅保留自然数中的非重复数,而将任何gcd先前发现的数大于1的数视为重复数,这是非常低效的,生成的素数数量是二次数。但这很优雅
Will Ness 2013年

优雅的IMO是Haskell的,import Data.List.Ordered ; let { _Y g = g (_Y g) ; primes = 2 : _Y( (3:) . minus [5,7..] . unionAll . map (\p-> [p*p, p*p+p*2..]) ) }但这当然是完全基于观点的
尼斯

Answers:


48

使用估计

pi(n) = n / log(n)

对于最多为n的质数找到极限,然后使用筛子。估计会低估最多n个素数的数量,因此筛子会比必要的要大一些,这可以。

这是我的标准Java筛子,在普通笔记本电脑上大约一秒钟即可计算出前百万个素数:

public static BitSet computePrimes(int limit)
{
    final BitSet primes = new BitSet();
    primes.set(0, false);
    primes.set(1, false);
    primes.set(2, limit, true);
    for (int i = 0; i * i < limit; i++)
    {
        if (primes.get(i))
        {
            for (int j = i * i; j < limit; j += i)
            {
                primes.clear(j);
            }
        }
    }
    return primes;
}

3
这是一个非常好的实现埃拉托色尼的筛
大卫·斯通

1
i <= Math.sqrt(limit)在外循环中循环是否足够?
Christoph

1
@David Johnstone不,pi(n)= n / log(n)低估了最多n个质数的数量,而质数的数量却相反。我很高兴您能找到更好的近似值。
starblue

1
如果您愿意在自己的循环中删除2的所有倍数,则可以使用j + = 2 * i作为循环增量来节省一些额外的运行时间,并且可以使用一次移位来计算一次
Nick Larsen

5
通过用BitSet实现2、3和5的车轮分解的类代替,它的速度几乎提高了3倍。
starblue 2010年

37

非常感谢所有提供有用答案的人。这是我在C#中找到前n个素数的几种不同方法的实现。前两种方法几乎是此处发布的方法。(海报名称在标题旁边。)我计划在某个时候进行Atkin筛分,尽管我怀疑这样做不会像现在的方法那样简单。如果有人能以任何方式改进这些方法,我很想知道:-)

标准方法彼得·斯密特jmserveraRekreativc

第一个素数为2。将其添加到素数列表中。下一个质数是下一个不能被该列表中的任何数字整除的数字。

public static List<int> GeneratePrimesNaive(int n)
{
    List<int> primes = new List<int>();
    primes.Add(2);
    int nextPrime = 3;
    while (primes.Count < n)
    {
        int sqrt = (int)Math.Sqrt(nextPrime);
        bool isPrime = true;
        for (int i = 0; (int)primes[i] <= sqrt; i++)
        {
            if (nextPrime % primes[i] == 0)
            {
                isPrime = false;
                break;
            }
        }
        if (isPrime)
        {
            primes.Add(nextPrime);
        }
        nextPrime += 2;
    }
    return primes;
}

通过仅测试除数直到被测数的平方根来优化这一点;并仅测试奇数。这可以通过仅测试形式的数字来进一步优化6k+[1, 5],或30k+[1, 7, 11, 13, 17, 19, 23, 29]等等

Eratosthenes筛starblue

这将找到k的所有素数。要列出前n个素数的列表,我们首先需要近似第n个素数的值。如此处所述,可以使用以下方法执行此操作。

public static int ApproximateNthPrime(int nn)
{
    double n = (double)nn;
    double p;
    if (nn >= 7022)
    {
        p = n * Math.Log(n) + n * (Math.Log(Math.Log(n)) - 0.9385);
    }
    else if (nn >= 6)
    {
        p = n * Math.Log(n) + n * Math.Log(Math.Log(n));
    }
    else if (nn > 0)
    {
        p = new int[] { 2, 3, 5, 7, 11 }[nn - 1];
    }
    else
    {
        p = 0;
    }
    return (int)p;
}

// Find all primes up to and including the limit
public static BitArray SieveOfEratosthenes(int limit)
{
    BitArray bits = new BitArray(limit + 1, true);
    bits[0] = false;
    bits[1] = false;
    for (int i = 0; i * i <= limit; i++)
    {
        if (bits[i])
        {
            for (int j = i * i; j <= limit; j += i)
            {
                bits[j] = false;
            }
        }
    }
    return bits;
}

public static List<int> GeneratePrimesSieveOfEratosthenes(int n)
{
    int limit = ApproximateNthPrime(n);
    BitArray bits = SieveOfEratosthenes(limit);
    List<int> primes = new List<int>();
    for (int i = 0, found = 0; i < limit && found < n; i++)
    {
        if (bits[i])
        {
            primes.Add(i);
            found++;
        }
    }
    return primes;
}

森达拉姆筛

我最近才发现这种筛子,但是可以很简单地实现它。我的实现速度不及Eratosthenes筛,但是它比朴素的方法要快得多。

public static BitArray SieveOfSundaram(int limit)
{
    limit /= 2;
    BitArray bits = new BitArray(limit + 1, true);
    for (int i = 1; 3 * i + 1 < limit; i++)
    {
        for (int j = 1; i + j + 2 * i * j <= limit; j++)
        {
            bits[i + j + 2 * i * j] = false;
        }
    }
    return bits;
}

public static List<int> GeneratePrimesSieveOfSundaram(int n)
{
    int limit = ApproximateNthPrime(n);
    BitArray bits = SieveOfSundaram(limit);
    List<int> primes = new List<int>();
    primes.Add(2);
    for (int i = 1, found = 1; 2 * i + 1 <= limit && found < n; i++)
    {
        if (bits[i])
        {
            primes.Add(2 * i + 1);
            found++;
        }
    }
    return primes;
}

仅供参考-我必须将您的主循环计数器更改为“ for(int i = 0; i * i <= limit && i * i> 0; i ++)”,以防止溢出。
Jacobs Data Solutions

Sundaram筛网的这种实现方法是其中极少数正确的方法之一。他们中的大多数人在计算i+j+2*i*j导致错误输出时对i和j使用错误的边界。
jahackbeth's

14

重新讨论一个老问题,但是在和LINQ玩时我偶然发现了这个问题。

此代码需要具有并行扩展名的.NET4.0或.NET3.5

public List<int> GeneratePrimes(int n) {
    var r = from i in Enumerable.Range(2, n - 1).AsParallel()
            where Enumerable.Range(1, (int)Math.Sqrt(i)).All(j => j == 1 || i % j != 0)
            select i;
    return r.ToList();
}

1
为什么这不是公认的答案?与接受的答案中的代码相比,此处的代码更短,更优雅,更快捷。希望我能投票一次以上!
Avrohom Yisroel

9

您处在良好的道路上。

一些评论

  • primes.Add(3); 使得该函数不适用于number = 1

  • 您不必用大于要测试数字平方根的质数来测试除法。

建议的代码:

ArrayList generatePrimes(int toGenerate)
{
    ArrayList primes = new ArrayList();

    if(toGenerate > 0) primes.Add(2);

    int curTest = 3;
    while (primes.Count < toGenerate)
    {

        int sqrt = (int) Math.sqrt(curTest);

        bool isPrime = true;
        for (int i = 0; i < primes.Count && primes.get(i) <= sqrt; ++i)
        {
            if (curTest % primes.get(i) == 0)
            {
                isPrime = false;
                break;
            }
        }

        if(isPrime) primes.Add(curTest);

        curTest +=2
    }
    return primes;
}

1
在循环中测试prime * prime <= curTest而不是预先计算平方根可能会使其更快,并使它更通用(适用于bignums等)
yairchu

为什么要使用平方根?这种选择的数学背景是什么?我,大概呆滞,只会除以2
路易斯·菲利佩

3
因为如果一个数具有素数,则其中至少一个必须小于或等于平方根。如果a * b = c且a <= b,则a <= sqrt(c)<= b。
David Johnstone 2009年

8

您应该看一下可能的素数。特别要看一下随机算法Miller-Rabin素数检验

为了完整起见,您可以只使用java.math.BigInteger

public class PrimeGenerator implements Iterator<BigInteger>, Iterable<BigInteger> {

    private BigInteger p = BigInteger.ONE;

    @Override
    public boolean hasNext() {
        return true;
    }

    @Override
    public BigInteger next() {
        p = p.nextProbablePrime();
        return p;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public Iterator<BigInteger> iterator() {
        return this;
    }
}

@Test
public void printPrimes() {
    for (BigInteger p : new PrimeGenerator()) {
        System.out.println(p);
    }
}

2
Miller-Rabbin速度非常快,代码非常简单。给予足够的迭代,使其具有足够的可靠性,可以就误报的可能性与随机CPU故障进行竞争。该算法的缺点是要理解其实际工作原理是一项艰巨的任务。
布赖恩2010年

6

绝不有效,但也许是最易读的:

public static IEnumerable<int> GeneratePrimes()
{
   return Range(2).Where(candidate => Range(2, (int)Math.Sqrt(candidate)))
                                     .All(divisor => candidate % divisor != 0));
}

与:

public static IEnumerable<int> Range(int from, int to = int.MaxValue)
{
   for (int i = from; i <= to; i++) yield return i;
}

实际上,这里只是一些帖子的变体,格式更好。


5

根据CC-BY-SA许可,由德国柏林圣维特姆13189版权所有2009, 网址为https://creativecommons.org/licenses/by-sa/3.0/

计算所有素数的最简单但最优雅的方法就是这种方法,但是这种方法很慢,并且由于使用了教师功能(!),因此对于较大的数,内存成本要高得多……但是它证明了Wilson Theoreme在通过Python中实现的算法生成所有素数

#!/usr/bin/python
f=1 # 0!
p=2 # 1st prime
while True:
    if f%p%2:
        print p
    p+=1
    f*=(p-2)

4

使用质数生成器创建primes.txt,然后:

class Program
{
    static void Main(string[] args)
    {
        using (StreamReader reader = new StreamReader("primes.txt"))
        {
            foreach (var prime in GetPrimes(10, reader))
            {
                Console.WriteLine(prime);
            }
        }
    }

    public static IEnumerable<short> GetPrimes(short upTo, StreamReader reader)
    {
        int count = 0;
        string line = string.Empty;
        while ((line = reader.ReadLine()) != null && count++ < upTo)
        {
            yield return short.Parse(line);
        }
    }
}

在这种情况下,我在方法签名中使用Int16,因此我的primes.txt文件包含从0到32767的数字。如果要将其扩展到Int32或Int64,您的primes.txt可能会更大。


3
引用OP:“我不介意使用哪种方法(天真或筛子或其他任何方法),但我确实希望它相当短并且显而易见其工作原理”。我认为我的回答是非常相关的。这也是最快的方法。
达琳·迪米特洛夫

14
即使他说“我不介意哪种方法...”,我也不认为这包括“打开素数列表”。这就像通过“购买计算机”回答“如何构建计算机”的问题。-1
stevenvh

8
如果您实际上在源代码本身中写质数,而不是从文件中读取它们,那会更快。
丹尼尔·达拉纳斯

3
消耗大量内存?不仅仅是将完整的素数列表作为文本读入...内存中?您知道.net中的字符串如何工作吗?
jmservera 2009年

6
素数列表是一个无限但不可变的列表,因此最好使用一个预先计算的列表,直到应用程序可能的上限。当有可用的正确公共列表可以满足要求时,为什么要浪费时间编写可能有错误的代码。
2009年

4

我可以提供以下C#解决方案。这绝不是很快,但它的作用非常清楚。

public static List<Int32> GetPrimes(Int32 limit)
{
    List<Int32> primes = new List<Int32>() { 2 };

    for (int n = 3; n <= limit; n += 2)
    {
        Int32 sqrt = (Int32)Math.Sqrt(n);

        if (primes.TakeWhile(p => p <= sqrt).All(p => n % p != 0))
        {
            primes.Add(n);
        }
    }

    return primes;
}

我没有进行任何检查-如果limit为负数或小于2(目前该方法将至少返回2作为质数)。但这很容易解决。

更新

使用以下两种扩展方法

public static void Do<T>(this IEnumerable<T> collection, Action<T> action)
{
    foreach (T item in collection)
    {
        action(item);
    }
}

public static IEnumerable<Int32> Range(Int32 start, Int32 end, Int32 step)
{
    for (int i = start; i < end; i += step)
    }
        yield return i;
    }
}

您可以按如下方式重写它。

public static List<Int32> GetPrimes(Int32 limit)
{
    List<Int32> primes = new List<Int32>() { 2 };

    Range(3, limit, 2)
        .Where(n => primes
            .TakeWhile(p => p <= Math.Sqrt(n))
            .All(p => n % p != 0))
        .Do(n => primes.Add(n));

    return primes;
}

它的效率较低(因为平方根经常被重新评估),但它甚至更干净。可以重写代码以延迟枚举素数,但这会使代码混乱很多。


我几乎肯定JIT编译器会优化平方根的计算(在启用优化的情况下进行编译)。您必须通过检查生成的程序集来验证这一点(IL只是部分优化,与JIT编译器执行的优化相去甚远。循环提升和其他微优化的时代已经过去了。实际上,有时试图智胜JIT会降低您的代码速度
Dave Black

4

是Eratosthenes筛子在C#中的实现:

    IEnumerable<int> GeneratePrimes(int n)
    {
        var values = new Numbers[n];

        values[0] = Numbers.Prime;
        values[1] = Numbers.Prime;

        for (int outer = 2; outer != -1; outer = FirstUnset(values, outer))
        {
            values[outer] = Numbers.Prime;

            for (int inner = outer * 2; inner < values.Length; inner += outer)
                values[inner] = Numbers.Composite;
        }

        for (int i = 2; i < values.Length; i++)
        {
            if (values[i] == Numbers.Prime)
                yield return i;
        }
    }

    int FirstUnset(Numbers[] values, int last)
    {
        for (int i = last; i < values.Length; i++)
            if (values[i] == Numbers.Unset)
                return i;

        return -1;
    }

    enum Numbers
    {
        Unset,
        Prime,
        Composite
    }

我会用布尔值而不是枚举来做到这一点
莱特曼

3

使用相同的算法,您可以缩短操作时间:

List<int> primes=new List<int>(new int[]{2,3});
for (int n = 5; primes.Count< numberToGenerate; n+=2)
{
  bool isPrime = true;
  foreach (int prime in primes)
  {
    if (n % prime == 0)
    {
      isPrime = false;
      break;
    }
  }
  if (isPrime)
    primes.Add(n);
}

3

我知道您要求使用非Haskell解决方案,但我将其包含在此处,因为它与问题有关,而且Haskell对于此类事情也很漂亮。

module Prime where

primes :: [Integer]
primes = 2:3:primes'
  where
    -- Every prime number other than 2 and 3 must be of the form 6k + 1 or 
    -- 6k + 5. Note we exclude 1 from the candidates and mark the next one as
    -- prime (6*0+5 == 5) to start the recursion.
    1:p:candidates = [6*k+r | k <- [0..], r <- [1,5]]
    primes'        = p : filter isPrime candidates
    isPrime n      = all (not . divides n) $ takeWhile (\p -> p*p <= n) primes'
    divides n p    = n `mod` p == 0

是的,我也是Haskell的忠实粉丝(我只是希望自己能更好地了解它)
David Johnstone 2009年

3

我使用LINQ在c#中编写了一个简单的Eratosthenes实现。

不幸的是,LINQ没有提供无限的整数序列,因此您必须使用int.MaxValue :(

我不得不以一种匿名类型来缓存候选sqrt,以避免为每个缓存的素数计算它(看起来有点难看)。

我使用以前素数的列表,直到候选者的sqrt

cache.TakeWhile(c => c <= candidate.Sqrt)

并检查每个从2开始的Int

.Any(cachedPrime => candidate.Current % cachedPrime == 0)

这是代码:

static IEnumerable<int> Primes(int count)
{
    return Primes().Take(count);
}

static IEnumerable<int> Primes()
{
    List<int> cache = new List<int>();

    var primes = Enumerable.Range(2, int.MaxValue - 2).Select(candidate => new 
    {
        Sqrt = (int)Math.Sqrt(candidate), // caching sqrt for performance
        Current = candidate
    }).Where(candidate => !cache.TakeWhile(c => c <= candidate.Sqrt)
            .Any(cachedPrime => candidate.Current % cachedPrime == 0))
            .Select(p => p.Current);

    foreach (var prime in primes)
    {
        cache.Add(prime);
        yield return prime;
    }
}

另一个优化是避免检查偶数,并在创建列表之前仅返回2。这样,如果调用方法只要求1个质数,它将避免所有混乱:

static IEnumerable<int> Primes()
{
    yield return 2;
    List<int> cache = new List<int>() { 2 };

    var primes = Enumerable.Range(3, int.MaxValue - 3)
        .Where(candidate => candidate % 2 != 0)
        .Select(candidate => new
    {
        Sqrt = (int)Math.Sqrt(candidate), // caching sqrt for performance
        Current = candidate
    }).Where(candidate => !cache.TakeWhile(c => c <= candidate.Sqrt)
            .Any(cachedPrime => candidate.Current % cachedPrime == 0))
            .Select(p => p.Current);

    foreach (var prime in primes)
    {
        cache.Add(prime);
        yield return prime;
    }
}

1
我希望我对LINQ有足够的了解,以便更好地理解和理解这个答案:-)另外,我感到这不是Eratosthenes筛子的实现,并且在概念上与我的原始功能相同(请查找下一个)无法被任何先前找到的素数整除的数字)。
David Johnstone 2009年

是的,但是“找到下一个无法被先前发现的质数除的数字(小于数字)”从概念上讲类似于橡皮擦的筛网。如果您愿意,即使您不熟悉LINQ,也可以对其进行一些重构以使其更具可读性。您熟悉迭代器吗?
Maghis,2009年

的事情,我喜欢这种方法的是,下一任的计算只是当主叫用户需要它,所以像“取前n个素数”或“采取更小的素数,则n”变得微不足道
Maghis

1
谢谢,但是我可以理解,它或多或少地知道它在做什么:-)我喜欢惰性评估,但是我仍然不会将其称为Eratosthenes筛子的实现。
戴维·约翰斯通

1

为了使它更加美观,您应该将IsPrime测试重构为一个单独的方法,并处理该方法之外的循环和增量。


1

我使用编写的功能库在Java中进行了此操作,但是由于我的库使用与Enumerations相同的概念,因此我确信代码可以适应:

Iterable<Integer> numbers = new Range(1, 100);
Iterable<Integer> primes = numbers.inject(numbers, new Functions.Injecter<Iterable<Integer>, Integer>()
{
    public Iterable<Integer> call(Iterable<Integer> numbers, final Integer number) throws Exception
    {
        // We don't test for 1 which is implicit
        if ( number <= 1 )
        {
            return numbers;
        }
        // Only keep in numbers those that do not divide by number
        return numbers.reject(new Functions.Predicate1<Integer>()
        {
            public Boolean call(Integer n) throws Exception
            {
                return n > number && n % number == 0;
            }
        });
    }
});

1

这是我很快想到的最优雅的产品。

ArrayList generatePrimes(int numberToGenerate)
{
    ArrayList rez = new ArrayList();

    rez.Add(2);
    rez.Add(3);

    for(int i = 5; rez.Count <= numberToGenerate; i+=2)
    {
        bool prime = true;
        for (int j = 2; j < Math.Sqrt(i); j++)
        {
            if (i % j == 0)
            {
                    prime = false;
                    break;
            }
        }
        if (prime) rez.Add(i);
    }

    return rez;
}

希望这有助于给您一个想法。我相信可以对其进行优化,但是它应该使您知道如何使您的版本更优雅。

编辑:如评论中所述,该算法的确为numberToGenerate <2返回了错误的值。我只想指出,我并不是想向他发布一种生成质数的好方法(请看Henri的答案),我只是在指出如何使他的方法更优雅。


3
这个返回错误的结果numberToGenerate <2
Peter Smit

是的,但是我没有设计算法,只是向他展示了如何使他的方法更优雅。因此,此版本与开头的问题同样错误。
DavidBožjak,2009年

1
我没有想到它被破坏了n = 1。我稍微更改了问题,以使该函数仅在n> 1时起作用:-)
David Johnstone 2009年

这允许素数平方作为素数。
尼斯,

1

Functional Java中使用基于流的编程,我想到了以下内容。该类型Natural本质上是BigInteger> = 0。

public static Stream<Natural> sieve(final Stream<Natural> xs)
{ return cons(xs.head(), new P1<Stream<Natural>>()
  { public Stream<Natural> _1()
    { return sieve(xs.tail()._1()
                   .filter($(naturalOrd.equal().eq(ZERO))
                           .o(mod.f(xs.head())))); }}); }

public static final Stream<Natural> primes
  = sieve(forever(naturalEnumerator, natural(2).some()));

现在您有了一个可以携带的价值,这是无穷无尽的素数。您可以执行以下操作:

// Take the first n primes
Stream<Natural> nprimes = primes.take(n);

// Get the millionth prime
Natural mprime = primes.index(1000000);

// Get all primes less than n
Stream<Natural> pltn = primes.takeWhile(naturalOrd.lessThan(n));

筛子的解释:

  1. 假设参数流中的第一个数字是质数,并将其放在返回流的最前面。返回流的其余部分是仅在需要时才生成的计算。
  2. 如果有人要求流的其余部分,请对参数流的其余部分调用sieve,过滤掉可被第一个数字整除的数字(除法余数为零)。

您需要具有以下导入:

import fj.P1;
import static fj.FW.$;
import static fj.data.Enumerator.naturalEnumerator;
import fj.data.Natural;
import static fj.data.Natural.*;
import fj.data.Stream;
import static fj.data.Stream.*;
import static fj.pre.Ord.naturalOrd;

1

我个人认为这是一个简短而干净的(Java)实现:

static ArrayList<Integer> getPrimes(int numPrimes) {
    ArrayList<Integer> primes = new ArrayList<Integer>(numPrimes);
    int n = 2;
    while (primes.size() < numPrimes) {
        while (!isPrime(n)) { n++; }
        primes.add(n);
        n++;
    }
    return primes;
}

static boolean isPrime(int n) {
    if (n < 2) { return false; }
    if (n == 2) { return true; }
    if (n % 2 == 0) { return false; }
    int d = 3;
    while (d * d <= n) {
        if (n % d == 0) { return false; }
        d += 2;
    }
    return true;
}

1

试试这个LINQ查询,它会生成您期望的质数

        var NoOfPrimes= 5;
        var GeneratedPrime = Enumerable.Range(1, int.MaxValue)
          .Where(x =>
            {
                 return (x==1)? false:
                        !Enumerable.Range(1, (int)Math.Sqrt(x))
                        .Any(z => (x % z == 0 && x != z && z != 1));
            }).Select(no => no).TakeWhile((val, idx) => idx <= NoOfPrimes-1).ToList();

1
// Create a test range
IEnumerable<int> range = Enumerable.Range(3, 50 - 3);

// Sequential prime number generator
var primes_ = from n in range
     let w = (int)Math.Sqrt(n)
     where Enumerable.Range(2, w).All((i) => n % i > 0)
     select n;

// Note sequence of output:
// 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
foreach (var p in primes_)
    Trace.Write(p + ", ");
Trace.WriteLine("");

0

这是一个python代码示例,可打印出200万以下的所有素数之和:

from math import *

limit = 2000000
sievebound = (limit - 1) / 2
# sieve only odd numbers to save memory
# the ith element corresponds to the odd number 2*i+1
sieve = [False for n in xrange(1, sievebound + 1)]
crosslimit = (int(ceil(sqrt(limit))) - 1) / 2
for i in xrange(1, crosslimit):
    if not sieve[i]:
        # if p == 2*i + 1, then
        #   p**2 == 4*(i**2) + 4*i + 1
        #        == 2*i * (i + 1)
        for j in xrange(2*i * (i + 1), sievebound, 2*i + 1):
            sieve[j] = True
sum = 2
for i in xrange(1, sievebound):
    if not sieve[i]:
        sum = sum + (2*i+1)
print sum

0

最简单的方法是反复试验:您尝试将2到n-1之间的任何数字除以候选质数n。
第一个快捷方式当然是a)您只需要检查奇数,b)您只需要检查不超过sqrt(n)的除法器。

就您而言,在此过程中您还生成了所有以前的素数,则只需检查列表中的任何素数(最大为sqrt(n))是否除以n。
应该是最快可以花钱买到的:-)

编辑
好,代码,您要的。但我警告您:-),这是5分钟快速且脏的Delphi代码:

procedure TForm1.Button1Click(Sender: TObject);
const
  N = 100;
var
  PrimeList: TList;
  I, J, SqrtP: Integer;
  Divides: Boolean;
begin
  PrimeList := TList.Create;
  for I := 2 to N do begin
    SqrtP := Ceil(Sqrt(I));
    J := 0;
    Divides := False;
    while (not Divides) and (J < PrimeList.Count) 
                        and (Integer(PrimeList[J]) <= SqrtP) do begin
      Divides := ( I mod Integer(PrimeList[J]) = 0 );
      inc(J);
    end;
    if not Divides then
      PrimeList.Add(Pointer(I));
  end;
  // display results
  for I := 0 to PrimeList.Count - 1 do
    ListBox1.Items.Add(IntToStr(Integer(PrimeList[I])));
  PrimeList.Free;
end;

1
您如何用代码表达这一点?:-)
David Johnstone 2009年

0

要找出前100个素数,可以考虑使用以下Java代码。

int num = 2;
int i, count;
int nPrimeCount = 0;
int primeCount = 0;

    do
    {

        for (i = 2; i <num; i++)
        {

             int n = num % i;

             if (n == 0) {

             nPrimeCount++;
         //  System.out.println(nPrimeCount + " " + "Non-Prime Number is: " + num);

             num++;
             break;

             }
       }

                if (i == num) {

                    primeCount++;

                    System.out.println(primeCount + " " + "Prime number is: " + num);
                    num++;
                }


     }while (primeCount<100);

0

我是通过先阅读Wikki上的“ Atkin筛子”以及一些先前的想法得出的-我花了很多时间从头开始编码,并对那些批评我的类似于编译器的非常密集的编码的人完全置零了风格+我什至没有尝试过运行代码...我已经学会使用的许多范例都在这里,只需阅读并哭泣,尽力而为。

绝对绝对要在使用前对所有这些进行真正的测试,以确保不要将其展示给任何人-这是为了阅读和考虑想法。我需要使素数工具正常工作,因此每次必须使某些东西正常工作时,这就是我开始的地方。

进行一次干净的编译,然后开始消除有缺陷的东西-我有将近1.08亿个可用代码击键以这种方式执行,...尽力而为。

我明天将处理我的版本。

package demo;
// This code is a discussion of an opinion in a technical forum.
// It's use as a basis for further work is not prohibited.
import java.util.Arrays;
import java.util.HashSet;
import java.util.ArrayList;
import java.security.GeneralSecurityException;

/**
 * May we start by ignores any numbers divisible by two, three, or five
 * and eliminate from algorithm 3, 5, 7, 11, 13, 17, 19 completely - as
 * these may be done by hand. Then, with some thought we can completely
 * prove to certainty that no number larger than square-root the number
 * can possibly be a candidate prime.
 */

public class PrimeGenerator<T>
{
    //
    Integer HOW_MANY;
    HashSet<Integer>hashSet=new HashSet<Integer>();
    static final java.lang.String LINE_SEPARATOR
       =
       new java.lang.String(java.lang.System.getProperty("line.separator"));//
    //
    PrimeGenerator(Integer howMany) throws GeneralSecurityException
    {
        if(howMany.intValue() < 20)
        {
            throw new GeneralSecurityException("I'm insecure.");
        }
        else
        {
            this.HOW_MANY=howMany;
        }
    }
    // Let us then take from the rich literature readily 
    // available on primes and discount
    // time-wasters to the extent possible, utilizing the modulo operator to obtain some
    // faster operations.
    //
    // Numbers with modulo sixty remainder in these lists are known to be composite.
    //
    final HashSet<Integer> fillArray() throws GeneralSecurityException
    {
        // All numbers with modulo-sixty remainder in this list are not prime.
        int[]list1=new int[]{0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,
        32,34,36,38,40,42,44,46,48,50,52,54,56,58};        //
        for(int nextInt:list1)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list1");//
            }
        }
        // All numbers with modulo-sixty remainder in this list are  are
        // divisible by three and not prime.
        int[]list2=new int[]{3,9,15,21,27,33,39,45,51,57};
        //
        for(int nextInt:list2)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list2");//
            }
        }
        // All numbers with modulo-sixty remainder in this list are
        // divisible by five and not prime. not prime.
        int[]list3=new int[]{5,25,35,55};
        //
        for(int nextInt:list3)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list3");//
            }
        }
        // All numbers with modulo-sixty remainder in
        // this list have a modulo-four remainder of 1.
        // What that means, I have neither clue nor guess - I got all this from
        int[]list4=new int[]{1,13,17,29,37,41,49,53};
        //
        for(int nextInt:list4)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list4");//
            }
        }
        Integer lowerBound=new Integer(19);// duh
        Double upperStartingPoint=new Double(Math.ceil(Math.sqrt(Integer.MAX_VALUE)));//
        int upperBound=upperStartingPoint.intValue();//
        HashSet<Integer> resultSet=new HashSet<Integer>();
        // use a loop.
        do
        {
            // One of those one liners, whole program here:
            int aModulo=upperBound % 60;
            if(this.hashSet.contains(new Integer(aModulo)))
            {
                continue;
            }
            else
            {
                resultSet.add(new Integer(aModulo));//
            }
        }
        while(--upperBound > 20);
        // this as an operator here is useful later in your work.
        return resultSet;
    }
    // Test harness ....
    public static void main(java.lang.String[] args)
    {
        return;
    }
}
//eof

0

试试这个代码。

protected bool isPrimeNubmer(int n)
    {
        if (n % 2 == 0)
            return false;
        else
        {
            int j = 3;
            int k = (n + 1) / 2 ;

            while (j <= k)
            {
                if (n % j == 0)
                    return false;
                j = j + 2;
            }
            return true;
        }
    }
    protected void btn_primeNumbers_Click(object sender, EventArgs e)
    {
        string time = "";
        lbl_message.Text = string.Empty;
        int num;

        StringBuilder builder = new StringBuilder();

        builder.Append("<table><tr>");
        if (int.TryParse(tb_number.Text, out num))
        {
            if (num < 0)
                lbl_message.Text = "Please enter a number greater than or equal to 0.";
            else
            {
                int count = 1;
                int number = 0;
                int cols = 11;

                var watch = Stopwatch.StartNew();

                while (count <= num)
                {
                    if (isPrimeNubmer(number))
                    {
                        if (cols > 0)
                        {
                            builder.Append("<td>" + count + " - " + number + "</td>");
                        }
                        else
                        {
                            builder.Append("</tr><tr><td>" + count + " - " + number + "</td>");
                            cols = 11;
                        }
                        count++;
                        number++;
                        cols--;
                    }
                    else
                        number++;
                }
                builder.Append("</table>");
                watch.Stop();
                var elapsedms = watch.ElapsedMilliseconds;
                double seconds = elapsedms / 1000;
                time = seconds.ToString();
                lbl_message.Text = builder.ToString();
                lbl_time.Text = time;
            }
        }
        else
            lbl_message.Text = "Please enter a numberic number.";

        lbl_time.Text = time;

        tb_number.Text = "";
        tb_number.Focus();
    }

这是aspx代码。

<form id="form1" runat="server">
    <div>
        <p>Please enter a number: <asp:TextBox ID="tb_number" runat="server"></asp:TextBox></p>

        <p><asp:Button ID="btn_primeNumbers" runat="server" Text="Show Prime Numbers" OnClick="btn_primeNumbers_Click" />
        </p>
        <p><asp:Label ID="lbl_time" runat="server"></asp:Label></p>
        <p><asp:Label ID="lbl_message" runat="server"></asp:Label></p>
    </div>
</form>

结果:不到一秒即可获得10000个质数

63秒内获得100000个质数

前100个质数的屏幕截图 在此处输入图片说明


1
尝试一下,我可以评估它的有效性和结果表示:请争论一下它的优雅。
灰胡子

结果样式只是增加的一部分。让我讨论一下将true / false作为素数返回的算法。n%2将消除一半的数字,因为偶数始终可被2整除。在其他代码中,我仅将其除以奇数,将可除数加二(因此下一个可整除也是奇数),直到该数字的一半为质数或不。为什么要减少一半,不要浪费时间,因为它将给我们零碎的答案。
2015年

log10(63)〜= 1.8,即您的数据显示n ^ 1.8的增长率。这很慢;Eratosthenes实现的最佳筛选exibit〜n ^ 1.01..1.05; 最佳试验区〜n ^ 1.35..1.45。您isPrimeNubmer确实实现了次优的Tril除法;当您尝试生成更多素数时,它的渐近性将恶化到大约n ^ 2(甚至更高)。
尼斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.