通过限制迭代次数来查找数字是否为Prime?c#

时间:2014-05-06 09:52:06

标签: c# primes

我想通过尽可能多地限制迭代次数来查找数字是否为素数。以下程序在博客中提出。我可以理解代码的这些部分..

public static bool Isprime(long i)
    {
        if (i == 1)
        {
            return false;
        }
        else if (i < 4)
        {
            return true;
        }
        else if (i % 2 == 0)
        {
            return false;
        }
        else if (i < 9)
        {
            return true;
        }
        else if (i % 3 == 0)
        {
            return false;
        }

但我不明白为什么f会增加6。

else
        {
            double r = Math.Floor(Math.Sqrt(i));
            int f = 5;
            while (f <= r)
            {
                if (i % f == 0) { return false; }
                if (i % (f + 2) == 0) { return false; }
                f = f + 6;
            }
            return true;
        }  
    }

4 个答案:

答案 0 :(得分:5)

因为每个素数(2和3除外)的形式为6k +/- 1 其他所有数字都不能成为素数,因为它们可以被2或3整除 此外,对您的方法进行一些修改:

public static bool Isprime(long i)
{
    if (i < 2)
    {
        return false;
    }
    else if (i < 4)
    {
        return true;
    }
    else if ((i & 1) == 0)
    {
        return false;
    }
    else if (i < 9)
    {
        return true;
    }
    else if (i % 3 == 0)
    {
        return false;
    }
    else
    {
        double r = Math.Floor(Math.Sqrt(i));
        int f = 5;
        while (f <= r)
        {
            if (i % f == 0) { return false; }
            if (i % (f + 2) == 0) { return false; }
            f = f + 6;
        }
        return true;
    }  
}
  • 您没有检查负数
  • 要检查数字是否均匀,(i&amp; 1)== 0更有效。不幸的是,i%3没有这样的技巧

答案 1 :(得分:1)

虽然我已经接受了一个好的答案,并且我之前提供了另一个答案,但我为ulong提供了一种新的方法,它可以帮助解释为什么6这个问题很重要。这使用for循环而不是while

UPDATE :我已经使用并行线程运行的版本扩展了这个答案。 See this CodeReview Link for the parallel version.

编辑:添加了许多复合材料的快速删除

public static bool IsPrime6(ulong number)
{
    // Get the quick checks out of the way.
    if (number < 2) { return false; }
    // Dispense with multiples of 2 and 3.
    if (number % 2 == 0) { return (number == 2); }
    if (number % 3 == 0) { return (number == 3); }

    // Another quick check to eliminate known composites.
    // http://programmers.stackexchange.com/questions/120934/best-and-most-used-algorithm-for-finding-the-primality-of-given-positive-number/120963#120963
    if (!( ((number - 1) % 6 == 0) || ((number + 1) % 6 == 0)) )
    {
        return false;
    }

    // Quick checks are over.  Number is at least POSSIBLY prime.
    // Must iterate to determine the absolute answer.
    // We loop over 1/6 of the required possible factors to check,
    // but since we check twice in each iteration, we are actually
    // checking 1/3 of the possible divisors.  This is an improvement
    // over the typical naive test of odds only which tests 1/2
    // of the factors.

    // Though the whole number portion of the square root of ulong.MaxValue
    // would fit in a uint, there is better performance inside the loop
    // if we don't need to implicitly cast over and over a few million times.
    ulong root = (ulong)(uint)Math.Sqrt(number);
    // Corner Case: Math.Sqrt error for really HUGE ulong.
    if (root == 0) root = (ulong)uint.MaxValue;

    // Start at 5, which is (6k-1) where k=1.
    // Increment the loop by 6, which is same as incrementing k by 1.
    for (ulong factor = 5; factor <= root; factor += 6)
    {
        // Check (6k-1)
        if (number % factor == 0) { return false; }
        // Check (6k+1)
        if (number % (factor + 2UL) == 0) { return false; }
    }

    return true;
}

这是基于数学定理,其表明每个素数&gt; 3可以表示为(6k +/- 1)。但这并不意味着形式的每个数字(6k + / 1)都是素数。

正确的反过来说,如果你有一个未表示为(6k +/- 1)的数字,那么这个数字就不能是素数。

以后与模运算符一起使用时,(6k-1)相当于(6(k + 1)+5)。

因此我们的意图是在5处开始循环,即k = 1的第一次出现(6k-1),在循环内检查(6k-1)和(6k + 1),然后增加通过6进行循环的另一次迭代。

简而言之,通过向前一个因子添加6进行迭代与向k添加1相同。

Ugly Explicit Casts的解释

在进一步测试表明对于这个算法他们没有什么区别之后,我拿出了UL个指示符。

<强>测试

要运行某些测试,您可以尝试:

const long  Largest63bitPrime =  9223372036854775783L;
const ulong Largest64bitPrime = 18446744073709551557UL;

在我的笔记本电脑上,最大的63位素数需要13秒,最大的64位素数需要18秒。令人惊讶的是,上述版本相对于(ulong)Largest63bitPrime比使用long的其他答案的while特定版本快1.5秒。

快速消除多种复合材料

根据对OP本身的评论,我添加了一张新支票。在这里找到最坏情况或最佳节省时间的情况有点困难。我针对Largest64bitPrime + 6测试了它。没有检查,它是14.2微秒,相比之下是1.1微秒。但现在包括在内以便算法被认为是完整的。

答案 2 :(得分:0)

请参阅@ Dennis_E的答案和解释,我给了+1。我提供了两种变体。这些陈述可能会有数以百万计的隐式演员阵容:

double r = Math.Floor(Math.Sqrt(i));
int f = 5;
while (f <= r)

循环条件隐式地将f强制转换为double。这掩盖了某些性能可能降低的地方。虽然long.MaxValue的平方根的整数部分可以放在uint中,但为了提高性能,最好将每个long保持为public static bool Isprime1(long number) { // Get the quick checks out of the way. if (number < 2) { return false; } // 2 and 3 are prime. if (number < 4) { return true; } // besides 2, any other even number, i.e. any other multiple of 2, is not prime. if ((number % 2) == 0) { return false; } // 5 and 7 are also prime. if (number < 9) { return true; } // multiples of 3 are not prime. if (number % 3 == 0) { return false; } // Quick checks are over. Must iterate to find the answer. // Though the whole number portion of the square root of long.MaxValue // would fit in a uint, there is better performance inside the loop // if we don't need to implicitly cast over and over a few million times. long root = (long)Math.Sqrt(number); long factor = 5; while (factor <= root) { if (number % factor == 0L) { return false; } if (number % (factor + 2L) == 0L) { return false; } factor = factor + 6L; } return true; } 。现在循环中的性能将受到任何隐式转换的影响。

public static bool Isprime2(long number)
{
    // Get the quick checks out of the way.
    if (number < 2) { return false; }
    // 2, 3, 5, & 7 are prime.
    if ((new long[] { 2L, 3L, 5L, 7L }).Contains(number)) { return true; }
    // any other multiples of 2 are not prime.
    if ((number % 2) == 0) { return false; }
    // any other multiples of 3 are not prime.
    if (number % 3 == 0) { return false; }
    // Quick checks are over.  Must iterate to find the answer.
    // Though the whole number portion of the square root of long.MaxValue
    // would fit in a uint, there is better performance inside the loop
    // if we don't need to implicitly cast over and over a few million times.
    long root = (long)Math.Sqrt(number);
    long factor = 5;
    while (factor <= root)
    {
        if (number % factor == 0L) { return false; }
        if (number % (factor + 2L) == 0L) { return false; }
        factor = factor + 6L;
    }
    return true;
}

以上所有内容都扩展了@Dennis_E的答案。另一种变化是:

sys.stdout.flush()

答案 3 :(得分:-1)

public class Prime {
public static void main(String[] args) {
    Scanner get=new Scanner(System.in);
    int n;
    System.out.println("Enter a number to find its primality");
    n=get.nextInt();
    System.out.println(n+" isPRime? "+isPrime(Math.ceil(Math.sqrt(n)),n));
}
private static boolean isPrime(double n,int k){
  boolean isPrim=true;
  int p=(int)n;
  for(int i=2;i<=p;i++){
      boolean iprime=false;
      for(int j=2;j<i/2;j++){
          if(i%j==0){
              iprime=true;
              break;
          }              
      }
      if(!iprime && k>i){
          if(k%i==0){
              isPrim=false;
              return isPrim;
            }
         }
       }
  return isPrim;
}
}