我的代码有问题。主题是编写一个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
请帮助,代码有什么问题?
答案 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
的更好版本:
// 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;
}