我希望我的程序找到最大的素数因子600851475143.例如,13195的素数因子是5,7,13和29,而29是最大的因子。虽然我的代码确实有效,但即使对于更小的输入,答案也需要很长时间,例如6kk(大约需要15秒。对于12kk,需要37秒,所以增量甚至比线性更差),这是100k次小于我应该用作输入的数字。下面是我的代码,非常感谢任何有关提高代码效率的帮助。
#include <stdio.h>
#include <math.h>
int main()
{
long long int number=600851475143;
int largest_prime_factor,i,j,k;
for (i=1;i<number/2;i+=2){
k=0;
j=3;
for (j=3;j<=sqrt(i);j+=2){
if (i%j==0){
k++;
break;
}
}
if (k==0){
if (number%i==0)
largest_prime_factor=i;
}
}
printf("The largest prime factor of 600851475143 is: %d",
largest_prime_factor);
return 0;
}
答案 0 :(得分:3)
您不需要浏览整个列表。一旦找到一个主要因素,您就可以将数字分解,并继续使用剩下的内容。
例如,举个例子:600,851,475,143。您可以快速找到它的第一个素数因子为71.如果您将600,851,475,143除以71得到8,462,696,833。除了71之外,这两个数字都具有相同的素数因子。因此,现在您可以搜索原始数字的最大因子,但搜索空间减少了2个数量级。
另外,请注意,如果数字本身是素数,您的代码将会失败。要解决此问题,请将最大数量初始化为
int largest_prime_factor = 1;
如果它最后仍为1,则返回数字本身。 (您可以使用number
初始化,但您很快就会明白为什么我选择1)
首先将2视为特例:
long long remain = number;
while (remain % 2 == 0) {
remain /= 2;
largest_prime_factor = 2;
}
然后在你的循环中做同样的事情。因为对于素数我们只需要检查其平方根,我们将我们的循环限制为两种情况,这取决于我们是否仍然认为该数字可能是素数。
最后,您修改的代码可能如下所示:
#include <stdio.h>
int main()
{
long long int number=600851475143;
long long largest_prime_factor = 1,i,j,k;
long long remain = number;
while (remain % 2 == 0) {
remain /= 2;
largest_prime_factor = 2;
/* Uncomment to see the factors
printf("2 ");*/
}
for (i=3; (largest_prime_factor == 1 && i*i <= number) ||
(largest_prime_factor > 1&& i <= remain); i+=2){
k=0;
j=3;
for (j=3; j*j<=i;j+=2){
if (i%j==0){
k++;
break;
}
}
if (k==0 && remain%i==0) {
largest_prime_factor=i;
while (remain % i == 0) {
/* Uncomment to see the factors
printf("%d ", i); */
remain /= i;
}
}
}
printf("The largest prime factor of %Ld is: %Ld",
number, largest_prime_factor);
return 0;
}
另请注意,其他变量也应该是类型(long long)。
瓶颈将是检查每个数字是否为素数,如果素因子本身很大,整个过程仍然会很慢。但是你可以获得更快的平均情况。对于您的示例,此算法在不到一秒的时间内得到因子71,839,1471和6857.
答案 1 :(得分:2)
您应该将sqrt(i)
移出for循环。它在每个循环中计算。 j*j <= i
也会比j <= sqrt(i)
快得多。
您的代码中存在错误:如果数字为long long int
,则其他变量应该过多或条件i<number/2
始终为真!
答案 2 :(得分:2)
一般来说,没有有效的方法:https://en.wikipedia.org/wiki/Integer_factorization#Difficulty_and_complexity
但是有很多方法可以提高代码的速度。看看那篇文章中的一些算法。
答案 3 :(得分:1)
此代码应该非常快,并且只需要几毫秒的数字600851475143:
long long int primes[1000];
int primesSize = 0;
long long int primeFactors[100];
int primeFactorsSize = 0;
long long int number = 600851475143ll;
for (long long int f = 2; f < number / 2; ++f)
{
// Check if f is a prime number
int primesIndex = 0;
while (primesIndex < primesSize && (f%primes[primesIndex]) != 0)
++primesIndex;
if (primesIndex >= primesSize)
{
primes[primesSize++] = f;
// Check if f is a prime factor of number
while ((number % f) == 0)
{
primeFactors[primeFactorsSize++] = f;
number /= f;
}
}
}
if (number != 1)
primeFactors[primeFactorsSize++] = number;
创建已找到的素数列表可以加快检查另一个可能的因素。
如果您找到了数字的主要因子,则将您的数字除以素因子并继续除法结果。也许这种划分必须多次完成。 number
中的最终值也是最重要的因素。
警告:我的代码根本没有经过测试。我确保number = 600851475143ll
的结果是正确的。此外,我使用的是C ++编译器,因此您可能需要进行一些小的更改。
对于较大的number
,您需要至少为primes
数组实现动态内存分配:
#include <stdlib.h>
#include <stdio.h>
int main()
{
long long int *primes = NULL;
int primesSize = 0;
int primesCapacity = 0;
long long int *primeFactors = NULL;
int primeFactorsSize = 0;
int primeFactorsCapacity = 0;
long long int number = 600851475143ll;
number = 13456769ll;
for (long long int f = 2; f < number / 2; ++f)
{
// Check if f is a prime number
int primesIndex = 0;
while (primesIndex < primesSize && (f%primes[primesIndex]) != 0)
++primesIndex;
if (primesIndex >= primesSize)
{
if (primesSize == primesCapacity)
{
primesCapacity += 1000;
primes = (long long int*)realloc(primes, primesCapacity * sizeof(long long int));
}
primes[primesSize++] = f;
// Check if f is a prime factor of number
while ((number % f) == 0)
{
if (primeFactorsSize == primeFactorsCapacity)
{
primeFactorsCapacity += 1000;
primeFactors = (long long int*)realloc(primeFactors, primeFactorsCapacity * sizeof(long long int));
}
primeFactors[primeFactorsSize++] = f;
number /= f;
}
}
}
if (number != 1)
{
if (primeFactorsSize == primeFactorsCapacity)
{
primeFactorsCapacity += 1000;
primeFactors = (long long int*)realloc(primeFactors, primeFactorsCapacity * sizeof(long long int));
}
primeFactors[primeFactorsSize++] = number;
}
printf("Last prime factor is %lld", primeFactors[primeFactorsSize-1]);
return 0;
}
答案 4 :(得分:0)
使用j * j&lt; = i代替j&lt; = sqrt(i),取决于我使用的数字的大小,使代码快5到10倍。 ++ K表;而不是k ++;也有轻微的影响。减少约0.5%。我还没有检查过一切。谢谢大家的宝贵意见!感谢他们,有许多事情需要思考和学习!