优化我的代码以查找给定整数的因子

时间:2012-10-05 18:27:03

标签: c++ factors

这是我的代码,但我想优化它。我不喜欢它在n的平方根之前测试所有数字的想法,考虑到一个人可能面临找到因素的事实大量的。你的答案会有很大的帮助。提前谢谢。

unsigned int* factor(unsigned int n)
{    
    unsigned int tab[40];
    int dim=0;
    for(int i=2;i<=(int)sqrt(n);++i)
    {
        while(n%i==0)
        {
            tab[dim++]=i;
            n/=i;
        }
    }
    if(n>1)
        tab[dim++]=n;
    return tab;
}

7 个答案:

答案 0 :(得分:5)

以下是关于如何在“正确的”c ++中执行此操作的建议(因为您标记为)。

PS。几乎忘了提及:我优化了对sqrt的调用:)

http://liveworkspace.org/code/6e2fcc2f7956fafbf637b54be2db014a

上查看
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>

typedef unsigned int uint;

std::vector<uint> factor(uint n)
{    
    std::vector<uint> tab;

    int dim=0;
    for(unsigned long i=2;i*i <= n; ++i)
    {
        while(n%i==0)
        {
            tab.push_back(i);
            n/=i;
        }
    }
    if(n>1)
        tab.push_back(n);
    return tab;
}

void test(uint x)
{
    auto v = factor(x);
    std::cout << x << ":\t";
    std::copy(v.begin(), v.end(), std::ostream_iterator<uint>(std::cout, ";"));
    std::cout << std::endl;
}

int main(int argc, const char *argv[])
{
    test(1);
    test(2);
    test(4);
    test(43);
    test(47);
    test(9997);
}

输出

1:  
2:  2;
4:  2;2;
43: 43;
47: 47;
9997:   13;769;

答案 1 :(得分:3)

如果您使用

... i*i <= n; ...

它的运行速度可能比i&lt; = sqrt(n)

快得多

顺便说一下,你应该尝试处理负数n的因素,或者至少确保你永远不会传递一个负数

答案 2 :(得分:3)

有一个简单的改变可以减少运行时间:将所有的2分解出来,然后只检查奇数。

答案 3 :(得分:1)

我怕你不能。地球上没有已知的方法可以在多项式时间内对大整数进行分解。但是,有一些方法可以帮助您略微(不显着)加速您的程序。搜索维基百科以获取更多参考。 http://en.wikipedia.org/wiki/Integer_factorization

答案 4 :(得分:1)

从你的解决方案中可以看出,你发现基本上所有的素数(条件while (n%i == 0))都是这样的,特别是对于大数字的情况,你可以预先计算素数,并且只检查那些素数。质数计算可以使用Sieve of Eratosthenes方法或其他一些有效的方法来完成。

答案 5 :(得分:1)

unsigned int* factor(unsigned int n)

如果unsigned int是典型的32位类型,则数字太小,无法获得任何更高级的算法。试验部门的通常增强当然是值得的。

如果您将除法移出循环2,并且仅在循环中除以奇数,如mentioned by Pete Becker,则基本上将输入数量所需的除法数减半,因此将功能加速了近2倍。

如果你更进一步并且还从循环中的除数中消除3的倍数,则减少分割数量,从而将速度提高一个因子接近3(平均而言;大多数数字不会有任何大的素数因子,但可以被2或3整除,对于那些加速度要小得多;但是这些数字反正很快。如果你考虑更长的数字范围,大部分时间花在因子上具有大质数除数的少数数字。)

// if your compiler doesn't transform that to bit-operations, do it yourself
while(n % 2 == 0) {
    tab[dim++] = 2;
    n /= 2;
}
while(n % 3 == 0) {
    tab[dim++] = 3;
    n /= 3;
}
for(int d = 5, s = 2; d*d <= n; d += s, s = 6-s) {
    while(n % d == 0) {
        tab[dim++] = d;
        n /= d;
    }
}

如果你经常调用这个函数,那么预先计算不超过65535的6542个素数,将它们存储在一个静态数组中,并且只用素数除以消除所有先验保证不存在的除法是值得的。找一个除数。

如果unsigned int恰好大于32位,那么使用一种更高级的算法将是有利可图的。您仍然应该从试验分割开始,找到小的素数因子(小的应该是<= 1000<= 10000<= 100000还是<= 1000000需要测试,我的肠道感觉说一个较小的值会平均更好)。如果在试验分割阶段之后,因子分解尚未完成,请使用例如,检查剩余因子是否为素数。 Miller-Rabin检验的确定性(对于所讨论的范围)变体。如果不是,请使用您最喜欢的高级算法搜索因子。对于64位数字,我建议Pollard's rho algorithm或椭圆曲线分解。 Pollard的rho算法更容易实现,并且这个数量的数字在相当的时间内找到因子,所以这是我的第一个建议。

答案 6 :(得分:0)

Int是小到遇到任何性能问题的方法。我只是尝试使用boost来测量算法的时间,但是无法获得任何有用的输出(太快)。所以你根本不用担心整数。

如果你使用i * i,我能够在15.097秒内计算出1.000.000个9位整数。优化算法是好的,但不是“浪费”时间(取决于你的情况),重要的是要考虑一个小的改进是否值得付出努力。有时候你必须问自己,你是否需要能够在10秒钟内计算出1.000.000英镑或者15英镑就可以了。