【问题标题】:Optimizing my code for finding the factors of a given integer优化我的代码以查找给定整数的因子
【发布时间】:2012-10-05 18:27:02
【问题描述】:

这是我的代码,但我想对其进行优化。我不喜欢在 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;
}

【问题讨论】:

  • 你有一个错误,你正在返回一个在堆栈上的数组。 factor() 返回后的任何其他调用都可能会覆盖您的数组。此外,不返回使用的数组的维度(dim)。
  • 作为参考,整数分解是难题之一。 (事实证明,公钥加密(阅读:SSL、RSA 等)依赖于它 已经足够困难了。)你真正能得到的最好结果就是测试所有 prime 介于 2 和平方根之间的数字,但是你也必须担心找到素数。

标签: c++ factors


【解决方案1】:

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

PS.差点忘了说:我优化了对sqrt away的调用:)

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;

【讨论】:

    【解决方案2】:

    有一个简单的更改会在一定程度上缩短运行时间:排除所有 2,然后只检查奇数。

    【讨论】:

      【解决方案3】:

      如果你使用

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

      它可能比 i 运行得快得多

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

      【讨论】:

      • 太好了,如果一个答案对你有帮助,你应该接受这个答案,这样以后看到这个问题的其他人都知道什么对你有帮助。
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        从您的解决方案中可以看出,您发现基本上所有素数(条件while (n%i == 0))都是这样工作的,尤其是对于大数的情况,您可以预先计算素数,然后只检查那些。素数的计算可以使用埃拉托色尼筛法或其他一些有效的方法。

        【讨论】:

        • 每找到一个因子,n的值就会改变,所以sqrt的旧值不再是当前n的平方根。不过,我还没有花时间弄清楚循环限制应该是多少。保留旧的 sqrt 值可能是正确的。
        • 是的,你是对的,很抱歉我查看了这一点,编辑了答案并删除了这一点。
        【解决方案6】:
        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 位,那么使用其中一种更高级的算法将是有利可图的。您仍然应该从试验部门开始找到小的主要因素(无论是小的应该意味着&lt;= 1000&lt;= 10000&lt;= 100000 还是可能需要测试&lt;= 1000000,我的直觉表明较小的值之一会平均而言更好)。如果在试除法阶段之后因式分解尚未完成,请使用例如检查剩余因子是否为素数。 Miller-Rabin 检验的确定性(针对所讨论的范围)变体。如果不是,请使用您最喜欢的高级算法搜索一个因子。对于 64 位数字,我建议使用 Pollard's rho algorithm 或椭圆曲线分解。 Pollard 的 rho 算法更容易实现,而且对于这么大的数字,可以在可比较的时间内找到因子,所以这是我的第一个建议。

        【讨论】:

        • 我应用了这个,它变得更快了..谢谢
        【解决方案7】:

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

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

        【讨论】:

        • 1mio 不是很多。 “计算整数”也不是目标。 OP特别说他需要更快地做到这一点。您的“答案”基本上声称他错了。 (哦,对于任何计算任务来说,15/s 是史前性能,实际上)
        • @sehe 对于任何计算任务来说都是史前的?夸大其词。操作员还说他想用整数来做这件事,这不是他的目标吗?我从来没有说过他错了。如果他说这太慢了(他只是说“如果可能的话”他需要更快),我会说不,你错了,而不是你的陈述是正确的,但我只是说这个算法已经相当快了。您是否对他的代码 (i*i) 和 5 个赞成的答案进行了性能测试?我对此表示怀疑,因为这样你就会明白我的意思,而且这个性能测试是在一台相当旧的电脑上进行的(应该这么说)
        猜你喜欢
        • 2012-01-28
        • 2017-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多