计算一个数字的质因数
Calculating the prime factors of a number
我有以下要求:
用
2 < n < 999999
查找给定数n
的素因数(不带其指数)。
我有以下算法可以解决问题,但似乎有一些性能问题:
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}
正如你所暗示的那样,你提出的算法效率非常低。但是对于规定的范围,对于具有 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) ;
我不打算解释这一点:通过自己弄清楚,你会学到更多。通过各种微优化,它可以做得更快一点,但它基本上是你规定的范围的最优选择,除非你使用素数表。这样的表格可能会让它更快一点,但在大多数情况下,这是不值得的。
主要优化:你不需要搜索到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;
}
对于如此有限的数字范围,硬编码最多 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
您不缓存任何结果:相反,您应该考虑使用
map<int,vector<int>> vPrimes
此映射将包含给定数字的所有素因数。例如,对于 50,它将包含 2,5 (2*5*5=50)。然后假设您尝试计算 300,然后进行测试 (300%3=0),然后将 3 添加到列表中,结果为 (2,3,5)。
希望有帮助,
来自维基百科:
大整数的因式分解被认为是计算上的 非常困难的问题,以及许多现代密码学的安全性 系统基于其不可行性。[注11]
最好的方法是通过埃拉托色尼的筛子或波拉德-罗算法来暴力破解素因数。因为数字不是那么大(最多 100000),所以你可以在现代硬件上非常快速地预先计算所有素因数。干杯
相关文章:
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 检查输入是否不是整数或数字
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 如何用数字处理log(0)
- 最高有效数字侧的第N位
- 如何获取一个数字的前3位
- 查找最接近的大于当前数字的数字的索引
- 找到两对数字,使它们的乘积的绝对差最小化
- 我想做一个彼此不同但重复出现的数字
- 将数字转换为字母(例如:123 转换为一二三)
- C++如何计算用户输入的数字中的偶数位数
- 如何在C++中确定文本文件中的元素是字符还是数字
- 打印数字图案
- C++问题:用户认为数字1-100,程序提出问题不超过6次即可得到答案。无法正确
- 如何检查一个c++字符串中有多少相同的字符/数字
- 欧拉项目 #3 获取数字的最大质因数
- 数字误差的质因数分解
- 计算一个数字的质因数
- 如何优化这个c程序来找到一个数字的质因数分解