用某种伪代码编写,你的意图似乎是
pe3 = last [x | x <- [2 .. 775146], isPrime x, rem 600851475143 x == 0]
阅读它:从 2 到 775146 范围内绘制,如果持有,如果为 0,则收集此类;返回最大的x
isPrime x
600851475143 % x
x
。我们也在此处编写(g x)
不带括号的应用程序,就像g x
.
计算余数比测试素数要便宜,所以我们将交换这两个操作:
pe3 n = last [x | x <- [2 .. isqrt n], rem n x == 0, isPrime x]
该算法可能适用于所涉及的特定数字,但不幸的是它通常是不正确的 - 例如对于整数平方根为 3000 的 9000009,它将返回 101。但9901是正确的答案(即 9901 是 9000009 的最大素数除数,而不是 101)。
让我们首先关注寻找最小的质因子,而不是:
pe3a n = head ([x | x <- [2 .. isqrt n], rem n x == 0, isPrime x] ++ [n])
为什么( ... ++ [n])
(++
意味着列表的串联)?因为如果n
它自己是素数,就根本找不到除数,而且第一个列表将返回空,[]
。在这种情况下,答案必须是n
它自己。但如果不是,那么答案就是head
除数列表的第一个(即 )。当然,当我们找到它时,我们不需要继续寻找更多。一个就足够了,如果最小的就是我们所需要的。
好的,所以尝试它(在一个虚构的惰性伪代码解释器上),我们得到 3 作为它的第一个因素:
> pe3a 9000009
3
现在我们可以从我们的数字中除以 3:
> div 9000009 3
3000003
并继续使用 3000003,而不是 9000009。这意味着我们可以停在它的平方根 1732 上,而不是停在 3000 上——效率上的巨大提升!此外,我们不需要从 2 重新开始——它已经过测试——我们可以从最后找到的因素开始:
pe3b (start, n) = (d, div n d)
where
d = head ([x | x <- [start .. isqrt n], rem n x == 0, isPrime x] ++ [n])
> pe3b (3, 3000003)
(3,1000001)
所以我们得到第二个 3,这个数字再次除以找到的除数。
> pe3b (3, 1000001)
(101,9901)
找到的下一个主要除数是 101,现在要分解的数字是 1000001 / 101 = 9901。我们再次从最后找到的除数 101 开始,因为所有较小的除数都已尝试过:
> pe3b (101, 9901)
(9901,1)
有趣的。isqrt(9901) == 99
,列表[101 .. 99]
为空,因此立即产生结果。9901 是它自身大于 100 的第一个因数,实际上大于 1,因为之前的所有数字都已经被依次尝试过,并且被除掉了。这意味着 9901 是素数,无需测试它的素数。
事实上,该算法找到的所有因子都可以通过相同的推理构造保证是素数,并且所有调用isPrime
都是多余的。
还要注意,这里执行除法(余数运算)的最大数字是 101,而不是3000。我们的新算法不仅正确,而且效率更高!
现在您可以在 Scheme 中编写这种重复pe3b
应用并除以最后找到的因子的算法。达到 1 时停止。
所以,在同一个伪代码中,
divStep (start, n) = (d, div n d)
where d = head ([x | x <- [start .. isqrt n], rem n x == 0] ++ [n])
pe3 n = fst . until ((== 1) . snd) divStep $ (2,n) -- (1st,2nd) in a tuple
factorizing n = takeWhile ((> 1) . fst) . drop 1 . iterate divStep $ (2,n)
factors n = map fst . factorizing $ n
isPrime n = factors n == [n]
读.
为$
“的”。until
pred step start是重复应用函数的高阶模式,直到满足谓词(((== 1) . snd)
意味着结果的第二个分量等于 1)。它通常在 Scheme 中用 named 编码let
。
要查看整个计算历史,iterate
step start是另一种模式,它收集所有中间结果(以及我们不需要的起始值,所以我们drop
使用它)。为了仅查看因子本身,我们将每个结果的第一个组成部分用map fst
. 一个数是素数,如果它是唯一的除数,大于 1,它本身。测试:
> pe3 9000009
9901
> factorizing 9000009
[(3,3000003),(3,1000001),(101,9901),(9901,1)]
> factors 9000009
[3,3,101,9901]
> pe3 600851475143
6857
> factorizing 600851475143
[(71,8462696833),(839,10086647),(1471,6857),(6857,1)] -- 1471 is the largest
> factors 600851475143 -- factor tried,
[71,839,1471,6857] -- *not* 775146 !!
> factors 600851475143999917 -- isqrt 600851475143999917 == 775146099
[41,37309,392798360393] -- isqrt 392798360393 == 626736