在用户输入的数字中找到最大的质数-C

时间:2019-02-14 11:01:31

标签: c

我的代码有问题。主题是编写一个C程序,该程序在用户输入的数字中找到最大的质数。

例如: 输入号码:46656665326

输出:66566653

这是我的代码:

#include <stdio.h>
#include <stdlib.h>

int is_prime(unsigned long long a)
{
    if(a<=1)
        return 0;
    if(a==2)
        return 1;
    for(unsigned long long p=2; p<a; p++)
        if(a%p==0)
            return 0;
    return 1;
}

unsigned long long find_largest_prime_number(unsigned long long number)
{
    unsigned long long prime=0;
    int count=0;
    unsigned long long count2=1;
    unsigned long long pom=0;
    unsigned long long pom3=0;
    pom3=number;
    while(pom3!=0)
    {
        count++;
        pom3/=10;
    }
    count++;
    int pom_1=0;
    while(pom_1<count)
    {
        count2*=10;
        pom_1++;
    }
    pom=number;
    while(count2>=10)
    {
        unsigned long long pom2=pom;
        while(pom2!=0)
        {
            if(is_prime(pom2))
                if(pom2>prime)
                    prime=pom2;
            pom2/=10;
        }
        count2/=10;
        pom=pom%count2;
    }
    return prime;
}

int main()
{
    unsigned long long x=0;
    printf("Enter number: ");
    int n1=scanf("%llu", &x);
    if(n1!=1)
    {
        printf("incorrect input");
        return 1;
    }
    printf("%llu", find_largest_prime_number(x));
    return 0;
}

问题在于它最多可以使用13位数字,但是当输入的数字超过13位时会冻结。 例如输入以下内容会冻结:215911504934497

请帮助,代码有什么问题?

4 个答案:

答案 0 :(得分:1)

阻止的原因归结为:

int is_prime(unsigned long long a)
{
    ...
    for(unsigned long long p=2; p<a; p++)
        if(a%p==0)
            return 0;
    return 1;
}

如果输入215911504934497,则find_largest_prime_number将呼叫is_prime(215911504934497)215911504934497是一个很大的数字,对于从2到a%p的每个p进行215911504934497的CPU成本很高(我认为至少您可以p < a/2)。您的程序陷入了这个循环。您可以通过在其中执行简单的printf来观察到这一点:

int is_prime(unsigned long long a)
{
    ...
    for(unsigned long long p=2; p<a; p++) {
        printf("%lld %lld\n", p, a);
        if(a%p==0)
            return 0;
    }
    return 1;
}

答案 1 :(得分:0)

专注于平方根终于解决了这个问题。 is_prime应该看起来像这样:

int is_prime(unsigned long long a)
{
    int i=0;
    int count=0;
    int test=0;
    int limit=sqrt(a)+1;
    if(a<=1)
        return 0;
    if(a==2)
        return 1;
    if(a%2==0)
        test=1;
    else
        for(i=3; i<limit && !test; i+=2, count++)
            if(a%i==0)
                test=1;
    if(!test)
        return 1;
    else
        return 0;
}

答案 2 :(得分:0)

您的代码是完全正确的。效率极低,因此仅花费很长的时间就可以确定一个大数是否是素数。

这是is_prime的更好版本:

  • 它只会测试除数,直到被测数的平方根。
  • 它仅测试奇数除数,如果数字不能被2整除,则测试是否可以被4、6、8等除是毫无意义的。

// long long integer square root found somewhere on the internet
unsigned long long isqrt(unsigned long long x)
{
  unsigned long long op, res, one;

  op = x;
  res = 0;

  /* "one" starts at the highest power of four <= than the argument. */
  one = 1LL << 62;  /* second-to-top bit set */
  while (one > op) one >>= 2;

  while (one != 0) {
    if (op >= res + one) {
      op -= res + one;
      res += one << 1;  // <-- faster than 2 * one  
    }
    res >>= 1;
    one >>= 2;
  }
  return res;
}


int is_prime(unsigned long long a)
{
  if (a <= 1 || a == 2 || a % 2 == 0)
    return 0;

  unsigned long long count = 0;
  unsigned long long limit = isqrt(a) + 1;

  for (unsigned long long p = 3; p < limit; p += 2)
  {
    if (a % p == 0)
      return 0;
  }
  return 1;
}

当然可以进行进一步的优化。例如。如果数字不能被3整除,则测试3的倍数也是没有意义的。另外,如果要查找一个质数范围,可能还需要考虑其他方法。

答案 3 :(得分:0)

如其他贡献者所述,在注释中,您的代码仅由于效率低下而“崩溃”。

许多其他贡献者使用更有效的方法来检查数字是否为质数,方法是对照数字除以其。

但是,这不是不是最有效的方法,尤其是当您是否有多个质数时。

为了使其更快,我建议实施the Sieve of Eratosthenes

#define MAX_N 4294967296 //idk how big of an array your computer can actually handle. I'm using 2^32 here.

//Declare as a global variable for extra memory allocation
//unsigned char is used as it is only 1 byte (smallest possible memory alloc)
//0 for FALSE, 1 for TRUE.
unsigned char is_prime[MAX_N+1];

//Populate the is_prime function up to your input number (or MAX_N, whichever is smaller)
//This is done in O(N) time, where N is your number.
void performSieve(unsigned long long number){
    unsigned long long i,j;
    unsigned long long n = (number>MAX_N)?MAX_N:number; //quick way (ternary operator): "whichever is smaller"

    //Populating array with default as prime
    for(i=2; i<=n; i++) is_prime[i] = 1;

    for(i=4; i<=n; i+=2) is_prime[i] = 0; //all even numbers except 4 is not prime
    for(i=3; i<=n; i+=2){
        if(is_prime[i] == 1)
            for(j=i*i;j<=n;j+=i){ //all the multiples of i except i itself are NOT prime
                is_prime[i] == 0;
            }
    }    
}

//isPrime function
unsigned char isPrime(unsigned long long n){
    if(n<=1) return 0; //edge cases

    //Check if we can find the prime number in our gigantic sieve
    if(n<=MAX_N){
        return is_prime[n]; //this is O(1) time (constant time, VERY FAST!)
    }

    //Otherwise, we now use the standard "check all the divisors" method
    //with all the optimisations as suggested by previous users:
    if(n%2==0) return 0; //even number

    //This is from user @Jabberwocky
    unsigned long long limit = isqrt(a);

    for (unsigned long long p = 3; p <= limit; p += 2) {
        if (a % p == 0) return 0;
    }

    return 1;
}