计算一个数的素因子

时间:2014-12-09 19:18:46

标签: c++ optimization prime-factoring

我有以下要求:

  

使用n找到给定数字2 < n < 999999的PRIME因子(没有指数)。

我有the following algorithm解决了这个问题,但似乎有一些性能问题:

bool is_prime(const unsigned long int &number) {
    for (unsigned long int i = 2; i <= sqrt(number); i++) {
        if (number%i == 0) return false;
    }
    return true;
}
unsigned long int next_prime(unsigned long int current) {
    current++;
    while (!is_prime(current)) {
        current++;
    }
    return current;
}

// THE PROBLEM SOLVER
vector<unsigned long int> find_divisors(const unsigned long int &n) {
    vector<unsigned long int> divisors;
    for (unsigned long int i = 2; i <= n; i = next_prime(i)) {
        if (n%i == 0) divisors.push_back(i);
    }
    return divisors;
}

问题:对于大数字,算法需要花费太多时间(对于允许的最大数量,需要 1.5秒)。

示例(正确):

  • n = 1620输出{2, 3, 5}
  • n = 2048输出{2}
  • n = 4096输出{2}

5 个答案:

答案 0 :(得分:1)

主要优化:您不需要搜索到n,您只需搜索到sqrt(n)即可。剩下的都是素数。二次优化:将你找到的素数除去,以减少你搜索的界限。

可以做得更多,但这已经快了大约一千倍。

vector<unsigned long int> find_divisors(const unsigned long int &m) {
  unsigned long int n = m;
  vector<unsigned long int> divisors;
  if (n%2 == 0) {
    divisors.push_back(2);
    while (n%2==0) n/=2;
  }

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

答案 1 :(得分:1)

对于如此有限的数字范围,硬编码最多1000个素数表是完全可以接受的。

int P[169]= {
    2,   3,   5,   7,  11,  13,  17,  19,  23,  29,  31,  37,  41,
   43,  47,  53,  59,  61,  67,  71,  73,  79,  83,  89,  97, 101,
  103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167,
  173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239,
  241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
  317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
  401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467,
  479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
  571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
  647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
  739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823,
  827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
  919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009          
};

int i= 0;
while (i < 169 && P[i] < Number)
{
    if (Number % P[i] != 0)
        i++;
    else
        Number/= P[i]; // P[i] is a factor
}
// Number is the last factor

答案 2 :(得分:1)

正如您所暗示的那样,您提出的算法非常低效。但是对于规定的范围,对于具有32位整数运算的计算机来说,这是一个非常简单的问题。这是怎么做的:

for (int p = 2 ; p * p <= n ; p = (p == 2) ? 3 : (p + 2)) { // p = 2,3,5,7,9,...until p > sqrt(n)
  if (n % p) continue ;
  divisors.push_back (p) ;       // p divides n, so save it
  do n /= p ; while (!(n % p)) ; // Remove all divisors p from n
}
if (n > 1) divisors.push_back (n) ;

我不打算解释这一点:你会通过自己搞清楚来学到更多。通过各种微观优化可以使它更快一些,但除非你使用素数表,否则它基本上是你所规定范围的最佳选择。这样的表可能会让它快一点,但在大多数情况下它不值得。

答案 3 :(得分:0)

您不会缓存任何结果: 相反,你应该考虑使用

map<int,vector<int>> vPrimes

此地图将包含给定数字的所有素因子。 例如,对于50,它将包含2,5(2 * 5 * 5 = 50)。 然后假设您尝试将其计算为300然后进行测试(300%3 = 0)然后将3添加到列表中,得到(2,3,5)。

希望有所帮助,

答案 4 :(得分:0)

来自维基百科的

  

大整数的因式分解被认为是计算上的   非常困难的问题,以及许多现代密码学的安全性   系统是基于其不可行性。[11]

你最好的方法是通过Eratosthenes&#39;来强制推动主要因素。筛或pollard-rho算法。因为数字不是那么大(最多100000),所以你可以在现代硬件上非常快速地预先计算所有素因子。 欢呼声