计算数字的最大素因数的最佳方法是什么?
我认为最有效的方法如下:
- 找到能完全除尽的最低素数
- 检查除法结果是否是素数
- 如果不是,则找到下一个最低素数
- 转到2。
我基于这个假设,因为计算小数更容易主要原因。 这大约是对的吗? 我还应该研究哪些其他方法?
编辑:我现在意识到,如果有超过 2 个素数因子在起作用,我的方法是徒劳的,因为当结果是其他两个素数的乘积时,步骤 2 会失败,因此需要递归算法。
再次编辑:现在我意识到这仍然有效,因为最后找到的素数必须是最大的素数,因此对步骤 2 中的非素数结果的任何进一步测试都会导致更小的素数。
What is the best approach to calculating the largest prime factor of a number?
I'm thinking the most efficient would be the following:
- Find lowest prime number that divides cleanly
- Check if result of division is prime
- If not, find next lowest
- Go to 2.
I'm basing this assumption on it being easier to calculate the small prime factors. Is this about right? What other approaches should I look into?
Edit: I've now realised that my approach is futile if there are more than 2 prime factors in play, since step 2 fails when the result is a product of two other primes, therefore a recursive algorithm is needed.
Edit again: And now I've realised that this does still work, because the last found prime number has to be the highest one, therefore any further testing of the non-prime result from step 2 would result in a smaller prime.
发布评论
评论(30)
我知道这不是一个快速的解决方案。 希望发布为更容易理解的缓慢解决方案。
I'm aware this is not a fast solution. Posting as hopefully easier to understand slow solution.
下面的 C++ 算法不是最好的算法,但它适用于十亿以下的数字,而且速度相当快
The following C++ algorithm is not the best one, but it works for numbers under a billion and its pretty fast
这是我快速计算最大素因数的方法。
它基于修改后的
x
不包含非素数因子的事实。 为了实现这一点,我们一旦找到一个因子就除x
。 那么剩下的就是返回最大的因数了。 它已经是最佳状态了。代码(哈斯克尔):
Here is my approach to quickly calculate the largest prime factor.
It is based on fact that modified
x
does not contain non-prime factors. To achieve that, we dividex
as soon as a factor is found. Then, the only thing left is to return the largest factor. It would be already prime.The code (Haskell):
在 C++ 中使用递归计算数字的最大素因数。 代码的工作原理解释如下:
Calculates the largest prime factor of a number using recursion in C++. The working of the code is explained below:
我正在使用继续将数字除以当前质因数的算法。
我在 python 3 中的解决方案:
输入:
10
输出:
5
输入:
600851475143
输出:
6857
I am using algorithm which continues dividing the number by it's current Prime Factor.
My Solution in python 3 :
Input :
10
Output :
5
Input :
600851475143
Output :
6857
这是我在 c# 中的尝试。 最后打印出来的是该数字的最大素因数。 我检查了一下,它有效。
Here is my attempt in c#. The last print out is the largest prime factor of the number. I checked and it works.
这是作为生成器提供的相同函数@Triptych,它也被稍微简化了。
然后可以使用以下方法找到最大素数:
以及使用以下方法找到的因子列表:
Here is the same function@Triptych provided as a generator, which has also been simplified slightly.
the max prime can then be found using:
and a list of factors found using:
我认为最好将所有可能的小于 n 的素数存储在某个地方,然后迭代它们以找到最大的除数。 您可以从 prime-numbers.org 获取素数。
当然我假设你的数字不会太大:)
I think it would be good to store somewhere all possible primes smaller then n and just iterate through them to find the biggest divisior. You can get primes from prime-numbers.org.
Of course I assume that your number isn't too big :)
Python 迭代方法,从数字中删除所有质因数
Python Iterative approach by removing all prime factors from the number
有一些模测试是多余的,因为如果所有因子 2 和 3 都被删除,n 永远不能被 6 除。 您只能允许 i 为素数,这在其他几个答案中有所显示。
实际上,您可以在这里交织埃拉托色尼筛:
为
sqrt(n)
。i 到新的
sqrt(n)
为止prime,并使用 while 循环代替。
列表。
另请参阅此问题。
There are some modulo tests that are superflous, as n can never be divided by 6 if all factors 2 and 3 have been removed. You could only allow primes for i, which is shown in several other answers here.
You could actually intertwine the sieve of Eratosthenes here:
to
sqrt(n)
.of i up to the new
sqrt(n)
as notprime, and use a while loop instead.
the list.
Also see this question.
在“James Wang”的网络上找到了这个解决方案
Found this solution on the web by "James Wang"
使用筛子的质因数:
Prime factor using sieve :
我猜,除了执行因式分解之外,没有直接的方法,就像上面的例子所做的那样,即
在迭代中,您确定数字N的“小”因子f,然后继续简化问题“找到具有候选因子 >=f 的 N':=N/f 的最大素因子”。
从一定大小的 f 开始,如果您对减少的 N' 进行素性测试,则预期搜索时间会更短,以防万一确认您的 N'< /em> 已经是初始 N 的最大质因数。
Guess, there is no immediate way but performing a factorization, as examples above have done, i.e.
in a iteration you identify a "small" factor f of a number N, then continue with the reduced problem "find largest prime factor of N':=N/f with factor candidates >=f ".
From certain size of f the expected search time is less, if you do a primality test on reduced N', which in case confirms, that your N' is already the largest prime factor of initial N.
这是我在 Clojure 中的尝试。 只走
素数?
的赔率和素数因子的素数,即。筛子
。 使用惰性序列有助于在需要之前生成值。Here is my attempt in Clojure. Only walking the odds for
prime?
and the primes for prime factors ie.sieve
. Using lazy sequences help producing the values just before they are needed.JavaScript 代码:
使用示例:
以下是代码示例:
JavaScript code:
Usage Example:
Here is an example of the code:
类似于 Triptych 的答案但也不同。 在此示例中,未使用列表或字典。 代码是用 Ruby 编写的
更新
感谢 Cooper Wolfe 的建议,算法得到了增强和优化。
Similar to Triptych's answer but also different. In this example, a list or dictionary is not used. Code is written in Ruby
UPDATED
Thanks to a suggestion by Cooper Wolfe, the algorithm has been enhanced and optimized.
实际上,有几种更有效的方法可以找到大数的因子(对于较小的数,试除法效果相当好)。
如果输入数字有两个非常接近其平方根的因子,则一种非常快的方法称为 Fermat因式分解。 它利用恒等式 N = (a + b)(a - b) = a^2 - b^2 并且易于理解和实现。 不幸的是,总体来说速度不是很快。
最著名的对 100 位以内的数字进行因式分解的方法是二次筛。 额外的好处是,该算法的一部分可以通过并行处理轻松完成。
我听说过的另一种算法是 Pollard 的 Rho 算法。 一般来说,它不如二次筛有效,但似乎更容易实现。
一旦您决定如何将数字拆分为两个因子,这是我能想到的查找数字最大质因子的最快算法:
创建一个最初存储数字本身的优先级队列。 每次迭代,您都会从队列中删除最大的数字,并尝试将其拆分为两个因素(当然,不允许 1 成为这些因素之一)。 如果此步骤失败,则该数字是素数,您就有了答案! 否则,您将这两个因素添加到队列中并重复。
Actually there are several more efficient ways to find factors of big numbers (for smaller ones trial division works reasonably well).
One method which is very fast if the input number has two factors very close to its square root is known as Fermat factorisation. It makes use of the identity N = (a + b)(a - b) = a^2 - b^2 and is easy to understand and implement. Unfortunately it's not very fast in general.
The best known method for factoring numbers up to 100 digits long is the Quadratic sieve. As a bonus, part of the algorithm is easily done with parallel processing.
Yet another algorithm I've heard of is Pollard's Rho algorithm. It's not as efficient as the Quadratic Sieve in general but seems to be easier to implement.
Once you've decided on how to split a number into two factors, here is the fastest algorithm I can think of to find the largest prime factor of a number:
Create a priority queue which initially stores the number itself. Each iteration, you remove the highest number from the queue, and attempt to split it into two factors (not allowing 1 to be one of those factors, of course). If this step fails, the number is prime and you have your answer! Otherwise you add the two factors into the queue and repeat.
我的答案是基于三联画的,但改进了很多。 它基于以下事实:除了 2 和 3 之外,所有素数的形式都是 6n-1 或 6n+1。
我最近写了一篇博客文章解释该算法的工作原理。
我敢说,一种不需要素性测试(并且不需要构造筛子)的方法会比使用这些方法的方法运行得更快。 如果是这样的话,这可能是这里最快的算法。
My answer is based on Triptych's, but improves a lot on it. It is based on the fact that beyond 2 and 3, all the prime numbers are of the form 6n-1 or 6n+1.
I recently wrote a blog article explaining how this algorithm works.
I would venture that a method in which there is no need for a test for primality (and no sieve construction) would run faster than one which does use those. If that is the case, this is probably the fastest algorithm here.
C 算法中的递归
可以是
下面是 C 语言问题的(尾)递归解决方案的示例:
该解决方案由三个函数组成。 一个用于测试候选因子是否是一个因子,另一个用于测试该因子是否是素数,最后一个用于将这两个因子组合在一起。
这里的一些关键思想是:
1- 在 sqrt(600851475143) 处停止递归
2- 仅测试奇数的因子性
3- 仅测试奇数的候选因子的素数
Recursion in C
Algorithm could be
Here's an example of a (tail)recursive solution to the problem in C:
The solution is composed of three functions. One to test if the candidate is a factor, another to test if that factor is prime, and finally one to compose those two together.
Some key ideas here are:
1- Stopping the recursion at sqrt(600851475143)
2- Only test odd numbers for factorness
3- Only testing candidate factors for primeness with odd numbers
最简单的解决方案是一对相互递归函数。
第一个函数生成所有素数:
第二个函数按升序返回给定数字 n 的质因数。
n
因数的数字。n
的最大质因数是第二个函数给出的最后一个数字。该算法需要一个惰性列表或具有按需调用语义的语言(或数据结构)。
为了澄清起见,这里是 Haskell 中上述内容的一个(低效)实现:
使其更快只是更聪明地检测哪些数字是素数和/或 n 的因子,但是算法保持不变。
The simplest solution is a pair of mutually recursive functions.
The first function generates all the prime numbers:
The second function returns the prime factors of a given number
n
in increasing order.n
.The largest prime factor of
n
is the last number given by the second function.This algorithm requires a lazy list or a language (or data structure) with call-by-need semantics.
For clarification, here is one (inefficient) implementation of the above in Haskell:
Making this faster is just a matter of being more clever about detecting which numbers are prime and/or factors of
n
, but the algorithm stays the same.所有数字都可以表示为素数的乘积,例如:
您可以通过简单地从 2 开始并继续除以直到结果不是您的数字的倍数来找到这些数字:
使用此方法您不必实际计算任何素数:它们都将是素数,基于这样的事实:您已经尽可能地将数字与所有前面的数字分解。
All numbers can be expressed as the product of primes, eg:
You can find these by simply starting at 2 and simply continuing to divide until the result isn't a multiple of your number:
using this method you don't have to actually calculate any primes: they'll all be primes, based on the fact that you've already factorised the number as much as possible with all preceding numbers.
在我看来,给出的算法的第二步并不是那么有效的方法。 你没有合理的期望它是素数。
此外,之前提出埃拉托斯特尼筛法的答案是完全错误的。 我刚刚编写了两个程序来分解 123456789。一个是基于 Sieve,一个是基于以下内容:
这个版本比 Sieve 快 90 倍。
问题是,在现代处理器上,操作类型远不如操作数量重要,更不用说上面的算法可以在缓存中运行,而 Sieve 则不能。 筛子使用大量运算来剔除所有合数。
另请注意,我在确定因素时对其进行划分减少了必须测试的空间。
It seems to me that step #2 of the algorithm given isn't going to be all that efficient an approach. You have no reasonable expectation that it is prime.
Also, the previous answer suggesting the Sieve of Eratosthenes is utterly wrong. I just wrote two programs to factor 123456789. One was based on the Sieve, one was based on the following:
This version was 90x faster than the Sieve.
The thing is, on modern processors the type of operation matters far less than the number of operations, not to mention that the algorithm above can run in cache, the Sieve can't. The Sieve uses a lot of operations striking out all the composite numbers.
Note, also, that my dividing out factors as they are identified reduces the space that must be tested.
第 1 部分。 Pollard-Rho + 审判部门。
受到你的问题的启发,我决定在 Python 中实现我自己的因式分解(并找到最大素因数)版本。
据我所知,可能最简单但非常高效的因式分解算法是 Pollard 的 Rho算法。 它的运行时间最多为
O(N^(1/4))
,比O(N^(1/2))
的时间快得多用于试除算法。 两种算法仅在复合(非质数)数的情况下才具有这些运行时间,这就是为什么应使用素性测试来过滤掉质数(不可因式分解)数。我在代码中使用了以下算法:费马素性测试 ...,Pollard 的 Rho 算法 ..., 试除算法。 在运行 Pollard's Rho 之前使用 Fermat 素性测试来过滤掉素数。 Trial Division 被用作后备方案,因为 Pollard 的 Rho 在极少数情况下可能无法找到因子,特别是对于一些较小的数字。
显然,将一个数字完全分解为素因数排序列表后,最大的素因数将是该列表中的最后一个元素。 在一般情况下(对于任何随机数),除了完全因式分解数字之外,我不知道有任何其他方法可以找出最大素因数。
作为我的代码中的一个示例,我正在分解 Pi 的前 190 小数位,代码在 1 秒内分解该数字,并显示最大的质因数,即 165 位(545位)的大小!
在线试用!
输出:
第 2 部分。 椭圆曲线法。
一段时间后,我决定通过从头开始实施更先进的椭圆曲线分解方法(称为 ECM)来改进我的帖子,请参阅维基百科文章 Lenstra 椭圆曲线分解。
此方法比我的回答帖子第 1 部分中描述的 Pollard Rho 快得多。 椭圆 ECM 方法的时间复杂度为
O(exp[(Sqrt(2) + o(1)) Sqrt(ln p ln ln p)])
,其中p
表示一个数的最小质因数。 而 Pollard Rho 的时间复杂度为O(Sqrt(p))
。 因此,对于足够大的最小 P 因子,ECM 要快得多。ECM方法的步骤:
检查数字是否小于2^16,然后通过试除法将其分解 方法。 返回结果。
检查数字是否可能是素数,因为我使用 费马测试 与32 次试验。 要克服卡迈克尔数,您可以使用米勒拉宾测试。 如果数字是素数,则将其作为唯一因子返回。
随机生成曲线参数
A, X, Y
并从曲线方程Y^2 = X^3 + AX + B (mod N)导出
。 检查曲线是否正常,值B
4 * A ** 3 - 27 * B ** 2
应为非零。通过埃拉托斯特尼筛法生成小素数,这些素数低于我们的界限。 每个素数都会提升到某个小幂,这个提升的素数将被称为 K。当它小于某个 Bound2 时,我会进行幂提升,在我的例子中,它是
Sqrt(Bound)
。计算椭圆点乘法
P = k * P
,其中 K 取自上一步,P 为 (X, Y)。 根据Wiki进行计算。点乘法使用模逆,计算
GCD(SomeValue, N)
根据Wiki。 如果这个 GCD 不是 1,那么它给出 N 的非 1 因子,因此在这种情况下,我通过异常并从 ECM 分解算法返回该因子。如果 Bound 之前的所有素数都相乘并且没有给出任何因子,则使用另一条随机曲线和更大的 Bound 再次重新运行 ECM 分解算法(上面的
1.-6.
)。 在我的代码中,我通过将 256 添加到旧边界来获取新边界。我的 ECM 代码中使用了以下子算法,所有提到的子算法都有相应维基百科文章的链接: Trial除法分解、费马概率检验、埃拉托斯特尼筛法(素数生成器),欧几里得算法(计算最大公约数,GCD),扩展欧几里得算法(带有 Bezu 系数的 GCD),模乘逆,从右到左二进制指数(用于椭圆点乘法),椭圆曲线算术(点加法和乘法),Lenstra 椭圆曲线分解。
与我的答案的第 1 部分不同,我对 Pi 数字 的数字进行因式分解,在第 2 部分我创建一个由
n = Prime(24) * Prime(35) * Prime(37) * ... 等组成的特殊数字
,这意味着数字是 24 的随机素数的乘积位、35 位、37 位等...这个自定义数字在视觉上更令人印象深刻,可以显示算法功能。正如我的答案的第 1 部分一样,我还使用多种方法来比较速度,并用更简单的方法分解出更小的因素。 所以在下面的代码中我使用 Trial Division + Pollard Rho + 椭圆曲线法。
在下面的代码之后,请查看控制台输出,以找出我的代码输出的好东西。
在线尝试!
控制台输出:
Part 1. Pollard-Rho + Trial Division.
Inspired by your question I decided to implement my own version of factorization (and finding largest prime factor) in Python.
Probably the simplest to implement, yet quite efficient, factoring algorithm that I know is Pollard's Rho algorithm. It has a running time of
O(N^(1/4))
at most which is much more faster than time ofO(N^(1/2))
for trial division algorithm. Both algos have these running times only in case of composite (non-prime) number, that's why primality test should be used to filter out prime (non-factorable) numbers.I used following algorithms in my code: Fermat Primality Test ..., Pollard's Rho Algorithm ..., Trial Division Algorithm. Fermat primality test is used before running Pollard's Rho in order to filter out prime numbers. Trial Division is used as a fallback because Pollard's Rho in very rare cases may fail to find a factor, especially for some small numbers.
Obviously after fully factorizing a number into sorted list of prime factors the largest prime factor will be the last element in this list. In general case (for any random number) I don't know of any other ways to find out largest prime factor besides fully factorizing a number.
As an example in my code I'm factoring first 190 fractional digits of Pi, code factorizes this number within 1 second, and shows largest prime factor which is 165 digits (545 bits) in size!
Try it online!
Output:
Part 2. Elliptic Curve Method.
Some time later I decided to improve my post by implementing from scratch more advanced elliptic curve factorization method that is called ECM, see Wikipedia Article Lenstra Elliptic Curve Factorization.
This method is considerably faster than Pollard Rho described in Part 1 of my answer post. Time complexity of elliptic ECM method is
O(exp[(Sqrt(2) + o(1)) Sqrt(ln p ln ln p)])
, wherep
signifies smallest prime factor of a number. While time complexity of Pollard Rho isO(Sqrt(p))
. So ECM is much much faster for big enough smallest P factor.Steps of ECM method:
Check if number is smaller than 2^16, then factor it through Trial Division method. Return result.
Check if number is probably prime with high condifence, for that I use Fermat Test with 32 trials. To overcome Carmichael numbers you may use Miller Rabin Test instead. If number is primes return it as only factor.
Generate curve parameters
A, X, Y
randomly and deriveB
from curve equationY^2 = X^3 + AX + B (mod N)
. Check if curve is OK, value4 * A ** 3 - 27 * B ** 2
should be non-zero.Generate small primes through Sieve of Eratosthenes, primes below our Bound. Each prime raise to some small power, this raised prime would be called K. I do raising into power while it is smaller than some Bound2, which is
Sqrt(Bound)
in my case.Compute elliptic point multiplication
P = k * P
, where K taken from previous step and P is (X, Y). Compute according to Wiki.Point multiplication uses Modular Inverse, which computes
GCD(SomeValue, N)
according to Wiki. If this GCD is not 1, then it gives non-1 factor of N, hence in this case I through an Exception and return this factor from ECM factorization algorithm.If all primes till Bound were multiplied and gave no factor then re-run ECM factorization algorithm (
1.-6.
above) again with another random curve and bigger Bound. In my code I take new bound by adding 256 to old bound.Following sub-algorithms were used in my ECM code, all mentioned sub-algorithms have links to corresponding Wikipedia articles: Trial Division Factorization, Fermat Probability Test, Sieve of Eratosthenes (prime numbers generator), Euclidean Algorithm (computing Greatest Common Divisor, GCD), Extended Euclidean Algorithm (GCD with Bezu coefficients), Modular Multiplicative Inverse, Right-to-Left Binary Exponentation (for elliptic point multiplication), Elliptic Curve Arithmetics (point addition and multiplication), Lenstra Elliptic Curve Factorization.
Unlike Part 1 of my answer where I factor digits of Pi number, here in Part 2 I create a special number composed of
n = Prime(24) * Prime(35) * Prime(37) * ... etc
, which means number as a product of Random prime numbers of 24 bits and 35 bits and 37 and etc... This custom number is more visually impressive to show algorithm capabilities.As in Part-1 of my answer I also use several methods to compare there speed and also to factor-out smaller factors with simpler methods. So in code below I use Trial Division + Pollard Rho + Elliptic Curve Method.
After code below see console output to figure out what nicde stuff my code outputs.
Try it online!
Console output:
首先计算一个存储素数的列表,例如 2 3 5 7 11 13 ...
每次对一个数进行素因式分解时,使用 Triptych 的实现,但迭代这个素数列表而不是自然整数。
Compute a list storing prime numbers first, e.g. 2 3 5 7 11 13 ...
Every time you prime factorize a number, use implementation by Triptych but iterating this list of prime numbers rather than natural integers.
对于 Java:
对于
int
值:对于
long
值:With Java:
For
int
values:For
long
values:这可能并不总是更快,但更乐观的是您找到一个大素数:
N
是您的数字return(N)
N 能被素数整除
,则Return(Prime)
编辑:在步骤 3 中,您可以使用埃拉托斯特尼筛法或阿特金斯筛法或任何您喜欢的方法,但筛子本身不会找到最大的素因数。 (这就是为什么我不会选择 SQLMenace 的帖子作为官方答案......)
This is probably not always faster but more optimistic about that you find a big prime divisor:
N
is your numberreturn(N)
Sqrt(N)
N is divisible by Prime
thenReturn(Prime)
Edit: In step 3 you can use the Sieve of Eratosthenes or Sieve of Atkins or whatever you like, but by itself the sieve won't find you the biggest prime factor. (Thats why I wouldn't choose SQLMenace's post as an official answer...)
这是我所知道的最好的算法(在 Python 中)
在最坏的情况下(当输入是素数时),上述方法的运行时间为 O(n) 。
编辑:
下面是
O(sqrt(n))
版本,如评论中所建议。 这是代码。Here's the best algorithm I know of (in Python)
The above method runs in
O(n)
in the worst case (when the input is a prime number).EDIT:
Below is the
O(sqrt(n))
version, as suggested in the comment. Here is the code, once more.