我正在尝试收集一些关于素数的统计数据,其中包括数 (prime-1)/2 的因子分布。我知道有统一选择的数字的因子大小的通用公式,但我还没有看到任何关于小于素数的因子的分布。
我编写了一个程序来迭代从 2^63 之后的第一个素数开始的素数,然后使用直到 2^32 的所有素数的试除法来分解 (素数 - 1)/2。但是,这非常慢,因为要迭代很多素数(和大量内存)。我将每个素数存储为一个字节(通过存储从一个素数到下一个素数的增量)。我还对最大 2^64 的数字使用 Miller-Rabin 素数检验的确定性变体,因此我可以轻松检测剩余值(成功除法后)何时为素数。
我已经尝试过使用 pollard-rho 和椭圆曲线分解的变体,但是很难在试除法和切换到这些更复杂的方法之间找到正确的平衡。另外我不确定我是否正确地实现了它们,因为有时它们似乎需要很长时间才能找到一个因素,并且基于它们的渐近行为,我希望它们对于这么小的数字会很快。
我还没有找到任何关于分解许多数字的信息(而不是试图分解一个),但似乎应该有一些方法可以利用这一点来加速任务。
非常感谢任何关于此问题的建议、替代方法的指针或其他指导。
编辑:我存储素数的方式是存储下一个素数的 8 位偏移量,隐含的第一个素数是 3。因此,在我的算法中,我有一个单独的除以 2 的检查,然后我开始一个循环:
factorCounts = collections.Counter()
while N % 2 == 0:
factorCounts[2] += 1
N //= 2
pp = 3
for gg in smallPrimeGaps:
if pp*pp > N:
break
if N % pp == 0:
while N % pp == 0:
factorCounts[pp] += 1
N //= pp
pp += gg
此外,我使用轮筛来计算试除的素数,并使用基于多个素数的余数的算法来获得给定起点之后的下一个素数。
我使用以下内容来测试给定的数字是否为素数(现在将代码移植到 c++):
bool IsPrime(uint64_t n)
{
if(n < 341531)
return MillerRabinMulti(n, {9345883071009581737ull});
else if(n < 1050535501)
return MillerRabinMulti(n, {336781006125ull, 9639812373923155ull});
else if(n < 350269456337)
return MillerRabinMulti(n, {4230279247111683200ull, 14694767155120705706ull, 1664113952636775035ull});
else if(n < 55245642489451)
return MillerRabinMulti(n, {2ull, 141889084524735ull, 1199124725622454117, 11096072698276303650});
else if(n < 7999252175582851)
return MillerRabinMulti(n, {2ull, 4130806001517ull, 149795463772692060ull, 186635894390467037ull, 3967304179347715805ull});
else if(n < 585226005592931977)
return MillerRabinMulti(n, {2ull, 123635709730000ull, 9233062284813009ull, 43835965440333360ull, 761179012939631437ull, 1263739024124850375ull});
else
return MillerRabinMulti(n, {2ull, 325ull, 9375ull, 28178ull, 450775ull, 9780504ull, 1795265022ull});
}