【发布时间】: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这个因素吗?不,当然不。这是检查所有可能因素后剩下的素数。
标签: c primes prime-factoring factoring