如何提高代码的效率?

时间:2016-12-06 12:48:45

标签: c performance

我希望我的程序找到最大的素数因子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;
}

5 个答案:

答案 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;
    }

然后在你的循环中做同样的事情。因为对于素数我们只需要检查其平方根,我们将我们的循环限制为两种情况,这取决于我们是否仍然认为该数字可能是素数。

  1. 仍然素数:测试到sqrt(数字)
  2. 不再是素数:测试直到最大因子超过剩余时间。
  3. 最后,您修改的代码可能如下所示:

    #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%。我还没有检查过一切。谢谢大家的宝贵意见!感谢他们,有许多事情需要思考和学习!