对于64位Prime,最快的因子(Prime-1)/ 2?

时间:2016-10-18 13:27:25

标签: python c++ prime-factoring factoring

我正在尝试收集关于素数的一些统计数据,其中包括数字因子(prime-1)/ 2的分布。我知道有统一选择数的因子大小的通用公式,但我还没有看到关于一个小于素数的因子分布的任何信息。

我已经编写了一个程序,在2 ^ 63之后从第一个素数开始迭代素数,然后使用试验除法将(prime-1)/ 2因子计算为2 ^ 32。然而,这是非常缓慢的,因为这是很多素数(和大量的内存)迭代。我将素数作为单个字节存储(通过存储从一个素数到下一个素数的增量)。我还使用米勒 - 拉宾素数检验的确定性变量来计算最多2 ^ 64的数字,因此我可以很容易地检测到剩余值(成功除法后)何时是素数。

我已经尝试使用pollard-rho和椭圆曲线分解的变体,但很难在试验分割和转换到这些更复杂的方法之间找到正确的平衡。另外我不确定我是否正确地实现了它们,因为有时它们似乎只花了很长时间才能找到一个因子,并且基于它们的渐近行为,我希望它们对于这么小的数字来说非常快。 / p>

我没有找到任何关于分解许多数字的信息(而不仅仅是试图考虑因素),但似乎应该有一些方法可以通过利用这个来加速任务。

非常感谢任何建议,对替代方法的指示或对此问题的其他指导。

编辑: 我存储素数的方法是将8位偏移存储到下一个素数,隐含的第一个素数为3.因此,在我的算法中,我有一个单独的除2检查,然后我开始一个循环:< / p>

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});
}

2 个答案:

答案 0 :(得分:2)

I don't have a definitive answer, but I do have some observations and some suggestions.

There are about 2*10^17 primes between 2^63 and 2^64, so any program you write is going to run for a while.

Let's talk about a primality test for numbers in the range 2^63 to 2^64. Any general-purpose test will do more work than you need, so you can speed things up by writing a special-purpose test. I suggest strong-pseudoprime tests (as in Miller-Rabin) to bases 2 and 3. If either of those tests shows the number is composite, you're done. Otherwise, look up the number (binary search) in a table of strong-pseudoprimes to bases 2 and 3 (ask Google to find those tables for you). Two strong pseudoprime tests followed by a table lookup will certainly be faster than the deterministic Miller-Rabin test you are currently performing, which probably uses six or seven bases.

For factoring, trial division to 1000 followed by Brent-Rho until the product of the known prime factors exceeds the cube root of the number being factored ought to be fairly fast, a few milliseconds. Then, if the remaining cofactor is composite, it will necessarily have only two factors, so SQUFOF would be a good algorithm to split them, faster than the other methods because all the arithmetic is done with numbers less than the square root of the number being factored, which in your case means the factorization could be done using 32-bit arithmetic instead of 64-bit arithmetic, so it ought to be fast.

Instead of factoring and primality tests, a better method uses a variant of the Sieve of Eratosthenes to factor large blocks of numbers. That will still be slow, as there are 203 million sieving primes less than 2^32, and you will need to deal with the bookkeeping of a segmented sieve, but considering that you factor lots of numbers at once, it's probably the best approach to your task.

I have code for everything mentioned above at my blog.

答案 1 :(得分:0)

这是我为以后存储素数的方法: (我假设你想要数字的因素,而不仅仅是素性测试。)

从我的网站http://chemicaldevelopment.us/programming/2016/10/03/PGS.html

复制

我假设你知道这部分的二进制数系统。如果没有,只需将1视为“是”,将0视为“否”。

因此,有很多算法可以生成前几个素数。我使用Eratosthenes的Sieve计算一个列表。

但是,如果我们将素数存储为数组,如[2,3,5,7],这将占用太多空间。确切的空间是多少?

那么,32位整数最多可以存储2 ^ 32个占用4个字节,因为每个字节是8位,32/8 = 4

如果我们想将每个黄金储存在2,000,000,000以下,我们将需要存储超过98,000,000,000。这会占用更多空间,并且在运行时比位集慢,这将在下面解释。

这种方法需要98,000,000个空格的整数(每个是32位,这是4个字节),当我们在运行时检查时,我们需要检查数组中的每个整数,直到找到它,或者我们找到一个数字比它大。

例如,假设我给你一小部分素数:[2,3,5,7,11,13,17,19]。我问你15岁是否是素数。你怎么告诉我的?

好吧,你会查看列表并将每个比较为15。

2 = 15?

3 = 15?

。 。

17 = 15?

此时,你可以停止,因为你已经过了15,所以你知道它不是素数。

现在,我们假设我们使用位列表来告诉您数字是否为素数。上面的列表如下所示:

001101010001010001010

从0开始,到19

1表示索引为素数,因此从左数开始计数:0,1,2

<强> 001 101010001010001010

粗体的最后一个数字是1,表示2是素数。

在这种情况下,如果我要求您检查15是否为素数,则无需查看列表中的所有数字;您需要做的就是跳到0。 。 。 15,检查那一位。

对于内存使用,第一种方法使用98000000个整数,而这个可以在一个整数中存储32个数字(使用1和0的列表),所以我们需要 2000000000/32 = 62500000整数。

因此它使用的内存大约是第一种方法的60%,而且使用起来要快得多。

我们将第二种方法中的整数数组存储在一个文件中,然后在运行时将其读回。

这使用250MB的ram来存储前2000000000个素数的数据。

您可以通过车轮筛分进一步减少这种情况(就像您存储的那样(prime-1)/ 2)

我会更多地进入砂轮筛。

你通过存储(prime - 1)/ 2得到了正确,而2是一个特例。

您可以将此扩展为 p#(第一个 p 素数的产物)

例如,您对数字 k 使用(1#)* k + 1

您还可以使用线性方程组(n#)* k + L ,其中 L 是小于 n#<的质数集/ strong>和1,不包括第一个 n 素数。

所以,你也可以存储 6 * k + 1 6 * k + 5 的信息,甚至更多,因为 L = {1,2,3,5} {2,3}

这些方法应该让你了解它背后的一些方法。

您需要在某种程度上实现此位集,例如32位整数列表或字符串。

查看:https://pypi.python.org/pypi/bitarray以获取可能的抽象