在C中找到大整数的所有质因子的更好方法?
Posted
技术标签:
【中文标题】在C中找到大整数的所有质因子的更好方法?【英文标题】:Better way to find all the prime factors of huge integers in C? 【发布时间】:2020-04-20 01:49:35 【问题描述】:我用 C 语言编写了一个代码,它基本上列出了一个巨大数字的所有质因数,它使用 gmp
库存储。这里是:
int is_div(mpz_t number, mpz_t i)
return mpz_divisible_p(number,i)!=0;
mpz_t * prime_divs(mpz_t number)
mpz_t * prime_dividers = NULL;
mpz_t i, i_squared,TWO, comp;
mpz_inits(i, i_squared, TWO, comp, NULL);
mpz_set_ui(i,2);
mpz_mul(i_squared, i ,TWO);
while(mpz_cmp(i_squared,number)<=0)
if(is_div(number,i))
mpz_fdiv_q(comp, number, i);
if(is_prime(i)) append(&prime_dividers,i);
if(is_prime(comp)) append(&prime_dividers,comp);
mpz_add_ui(i,i,1);
mpz_mul(i_squared, i ,i);
mpz_clears(i, i_squared, TWO, comp, NULL);
return prime_dividers;
请注意,这里没有定义函数int is_prime(mpz_t n)
,因为它很长。只要知道它是米勒拉宾素性检验的确定性变体(最多 3,317,044,064,679,887,385,961,981)的实现。函数void append(mpz_t** arr, mpz_t i)
也是如此,它只是一个将其附加到列表的函数。
所以我的prime_divs
函数在[2,sqrt(number)]
范围内搜索除number
的所有整数i
。如果是这种情况,它然后计算它的互补除数(即number/i
)并确定它们中的任何一个是否是素数。如果这些整数是素数,那么它们将使用append
附加到一个列表中。
有什么方法可以让prime_divs
更快?
【问题讨论】:
Erathosthenes 的筛子比确定性的 Miller-Rabin 对大量数字慢得多。 但是测试[2, sqrt(number)]
范围内的每个数字可能会否定使用 M-R 获得的任何效率。您至少应该将循环限制为奇数,因为唯一的偶数是2
。
GMP 源 tarball 在 demos 目录中包含一个程序 factorize.c
,它实现了 Pollard's rho algorithm。这不是已知的用于分解大整数的最快算法,但它比新算法更容易理解。
您可以通过在每次循环中将 2 添加到 i 来立即将速度加倍(在首先检查 2 和 3 之后)。这样你只测试奇数除数。您可以使用更复杂的模式来剔除更多因素(例如,一旦超过 3,只测试 1 或 5 mod 6 的除数)。图案越大,您必须走得越远才能应用它。
@Michael 你的反对毫无意义。对于 348,它是这样的:首先找到因子 2,它出现了两次。所以你除以 4 得到 87。然后你继续寻找,你找到了 3,它出现了一次。所以你除以 3 得到 29。然后你继续查找 sqrt(29),但找不到其他因素。这意味着 29 必须是素数,所以你完成了:348 = 2*2*3*29。这是非常非常简单的。你错过了29这个因素吗?不,当然不。这是检查所有可能因素后剩下的素数。
【参考方案1】:
我怀疑您可以通过首先检查小的除数来节省时间。使用埃拉托色尼筛法建立一个低于 5,000 或 10,000 的素数列表。然后使用该列表查找大数字中的小因素(如果有的话)。每次你找到一个因子(可能多次找到同一个因子)时,将那个因子除以减少目标数字的大小。
当您用尽小素数列表时,可能值得在尝试分解大残差之前对其进行快速素性检查。这避免了浪费大量时间寻找大素数的因子。您需要测试这个想法,看看它是否真的为您节省了时间。
只有这样你才能调用 M-R 检验来找出剩余的因素。
【讨论】:
以上是关于在C中找到大整数的所有质因子的更好方法?的主要内容,如果未能解决你的问题,请参考以下文章