在输入的数字后找到第一个素数

时间:2018-11-16 14:24:50

标签: c loops

我试图找到n之后的第一个素数,除非输入的n已经是素数(然后程序打印出n并终止)。

示例输入:

n = 7

The first prime number is: 7 (好)

n = 591

The first prime number is: 591(不正确,591不是质数)

n = 14

The first prime number is: 15(这也是错误的,不是17吗?)

我在哪里出错?这可能是显而易见的,但是我才刚开始。

#include <stdio.h>

int main(){

int i = 2, n, m;

printf("n = ");

do
scanf("%d", &n);
while (n < 2);

m = n / 2;

if (n == 2){
    printf("The first prime number is: %d", n);
    return 0;
}

while ( i <= m ){

    if (n % i == 0)
        n++;

        if (n % i != 0){
            printf("The first prime number is: %d", n);
            return 0;
        }   else i++;

}

return 0;
}

3 个答案:

答案 0 :(得分:2)

您确定质数的逻辑是错误的。

首先,您应该编写一个函数(不一定是推荐的),以检查一个数字是否为质数。这是此功能的代码:

    int checkPrimeNumber(int n)
    {
        int j, flag = 1;

        for(j=2; j <= n/2; ++j)
        {
            if (n%j == 0)
            {
                flag =0;
                break;
            }
        }
        return flag;
    }

一旦包含函数,您的while循环应循环执行,直到使用该函数找到从N开始的第一个质数为止。下面是该函数的代码。

您也可以在这里查看以下答案: https://codereview.stackexchange.com/questions/71212/find-smallest-prime-number-greater-than-given-n

答案 1 :(得分:2)

以下两个逻辑应该可以解决您的问题。

int IsPrime(int n)
{
    int i;
    for( i=2; i <= n/i; i++)
        if( n%i == 0 ) return 0;
    return 1;
}

此函数可以合理地快速确定传入的整数是否为素数。通过测试整数的平方根后,它将停止测试。

int FirstPrime(int n)
{
    while( !IsPrime(n) )
        n++;
    return n;
}

此函数包含您的问题陈述中列出的基本逻辑:返回输入值(如果为质数),或者使该值后的第一个整数为质数失败。

将代码分成单独的函数可以使测试和推理代码变得更加容易。

答案 2 :(得分:0)

检查素数

这是我用于检测素数的简单代码:

int isprime(unsigned number)
{
    if (number <= 1)
        return 0;
    if (number == 2 || number == 3)
        return 1;
    if (number % 2 == 0 || number % 3 == 0)
        return 0;
    for (unsigned x = 5; x * x <= number; x += 6)
    {
        if (number % x == 0 || number % (x + 2) == 0)
            return 0;
    }
    return 1;
}

它利用了一个事实,即所有大于3的素数都具有6N±1的形式。很容易明白为什么。形式6N + 0、6N + 2、6N + 4的所有数字都可以清楚地除以2,形式6N + 3的数字可以清楚地被3除尽,从而仅留下6N + 1和6N + 5作为质数—和6N + 5等效于6(N + 1)-1,因此公式6N±1正确覆盖了它们。对于N = 1,6N±1产生5和7,它们是素数; N = 2产生素数11和13; N = 3产生质数17和19; N = 4产生23和25,其中23是质数,而25不是。所有大于3的素数均具有6N±1的形式;并非所有形式为6N±1的数字都是质数。所有这些意味着,代码在遍历范围直至数字的平方根时,只会检查每六个中的两个除数。

我有一个更复杂的变体,它知道素数最多为100,然后每6步一次:

int isprime(unsigned number)
{
    if (number <= 1)
        return 0;
    if (number == 2 || number == 3)
        return 1;
    if (number % 2 == 0 || number % 3 == 0)
        return 0;
    static const unsigned int small_primes[] =
    {
         5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
        53, 59, 61, 67, 71, 73, 79, 83, 87, 89, 91, 97
    };
    enum { NUM_SMALL_PRIMES = sizeof(small_primes) / sizeof(small_primes[0]) };
    for (unsigned i = 0; i < NUM_SMALL_PRIMES; i++)
    {
        if (number == small_primes[i])
            return 1;
        if (number % small_primes[i] == 0)
            return 0;
    }
    for (unsigned i = 101; i * i <= number; i += 6)
    {
        if (number % i == 0 || number % (i + 2) == 0)
            return 0;
    }
    return 1;
}

这通常比另一个要快一些,但数量很少。

之后的下一个素数

我最初是为另一个SO问题编写此代码的,但在发布答案之前已将其删除。它使用isprime()的另一个变体,其质数表最大为1013。

/* Inspired by the deleted question SO 5308-6674 */
/* Determine the next prime after a given number */

#include <assert.h>
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>

#define NEXT_PRIME_AFTER    /* Avoid unnecessary checks in is_prime() */

#ifdef TEST
static unsigned primes[] = { 2, 3, 5, 7, 11 };
#else
static unsigned primes[] =
{
       2,    3,    5,    7,   11,   13,   17,   19,   23,   29,
      31,   37,   41,   43,   47,   53,   59,   61,   67,   71,
      73,   79,   83,   89,   97,  101,  103,  107,  109,  113,
     127,  131,  137,  139,  149,  151,  157,  163,  167,  173,
     179,  181,  191,  193,  197,  199,  211,  223,  227,  229,
     233,  239,  241,  251,  257,  263,  269,  271,  277,  281,
     283,  293,  307,  311,  313,  317,  331,  337,  347,  349,
     353,  359,  367,  373,  379,  383,  389,  397,  401,  409,
     419,  421,  431,  433,  439,  443,  449,  457,  461,  463,
     467,  479,  487,  491,  499,  503,  509,  521,  523,  541,
     547,  557,  563,  569,  571,  577,  587,  593,  599,  601,
     607,  613,  617,  619,  631,  641,  643,  647,  653,  659,
     661,  673,  677,  683,  691,  701,  709,  719,  727,  733,
     739,  743,  751,  757,  761,  769,  773,  787,  797,  809,
     811,  821,  823,  827,  829,  839,  853,  857,  859,  863,
     877,  881,  883,  887,  907,  911,  919,  929,  937,  941,
     947,  953,  967,  971,  977,  983,  991,  997, 1009, 1013,
};
#endif /* TEST */

enum { N_PRIMES = sizeof(primes) / sizeof(primes[0]) };

/*
** In the context of next_prime_after(), this function is never called
** upon to validate small numbers - numbers less than primes[N_PRIMES-1]
** are not passed here.  In more general contexts, the extra conditions
** in the conditionally compiled code are necessary for accuracy.
*/
static bool is_prime(unsigned p)
{
    for (int i = 0; i < N_PRIMES; i++)
    {
#ifndef NEXT_PRIME_AFTER
        if (p < primes[i])
            return false;
        if (p == primes[i])
            return true;
#endif /* NEXT_PRIME_AFTER */
        if (p % primes[i] == 0)
            return false;
    }
    for (unsigned t = primes[N_PRIMES - 1]; t * t <= p; t += 6)
    {
        if (p % t == 0)
            return false;
        if (p % (t + 2) == 0)
            return false;
    }
    return true;
}

static unsigned next_prime_after(unsigned start)
{
    for (int i = 0; i < N_PRIMES; i++)
    {
        if (start < primes[i])
            return primes[i];
    }
    for (unsigned x = (start + 1) / 6; x < UINT_MAX / 6; x++)
    {
        unsigned t = 6 * x - 1;
        if (t > start && is_prime(t))
            return(t);
        t += 2;
        if (t > start && is_prime(t))
            return(t);
    }
    return 0;
}

int main(void)
{
    assert((primes[N_PRIMES-1]+1) % 6 == 0);
    for (unsigned u = 0; u < 100; u++)
        printf("%3u => %3u\n", u, next_prime_after(u));
    for (unsigned t = 100, u = next_prime_after(t); u < 12345678; t = u)
        printf("%3u => %3u\n", t, (u = next_prime_after(t)));
}

请注意此处的isprime()函数。它是针对这种情况而量身定制的,并省略了通用独立测试仪所需的检查。 next_prime_after()逐步遍历已知素数的列表(如果您可能要处理许多可能的素数,则可以添加测试以查看是否值得完全经历第一个循环),然后逐步执行6N±1序列以寻找素数。

测试代码在从0到99的每个数字之后打印下一个素数。此后,它将逐步遍历素数,直到12345701(这是12345678之后的第一个素数)。

  0 =>   2
  1 =>   2
  2 =>   3
  3 =>   5
  4 =>   5
  5 =>   7
  6 =>   7
  7 =>  11
  8 =>  11
  9 =>  11
 10 =>  11
 11 =>  13
 12 =>  13
 13 =>  17
 14 =>  17
 15 =>  17
 16 =>  17
 17 =>  19
 18 =>  19
 19 =>  23
 20 =>  23
 21 =>  23
 22 =>  23
 23 =>  29
…
 95 =>  97
 96 =>  97
 97 => 101
 98 => 101
 99 => 101
100 => 101
101 => 103
103 => 107
107 => 109
109 => 113
113 => 127
127 => 131
…
12345581 => 12345623
12345623 => 12345637
12345637 => 12345643
12345643 => 12345647
12345647 => 12345653
12345653 => 12345701