这个问题我试图回答:
的13195的首要因素是5,7,13和29是什么号码600851475143的最大质因数?
我要去哪里错了? 我的黄金? 测试似乎是问题,但它适用于相对较少的罚款。 然而黄金? 测试给出了错误的答案用更大的数字。 是否有更简单的方法来进行此事?
(define b 3)
(define z 0)
(define divides?
(lambda (a b)
(= (remainder a b) 0)))
(define (prime? n)
(cond
((or (= n 1) (= n 0)) false)
((even? n) false)
((= n 2) true)
((= n b) true)
((divides? n b) false)
(else (and (set! b (+ b 1)) (prime? n)))))
;Largest Prime Factor Test
(define (LPF x)
(cond
((divides? 600851475143 x)
(cond
((prime? x)
(cond
((> x z) (set! z x)))))))
(if (< x 775146) (LPF (+ x 1)) (display z)))
写在一定的伪代码,你的意图似乎是
pe3 = last [x | x <- [2 .. 775146], isPrime x, rem 600851475143 x == 0]
读取它: 对于x
从范围2吸引到775146,如果isPrime x
成立,如果600851475143 % x
0,收集这样x
; 返回最大 。 我们还编写应用程序(gx)
这里没有括号,如刚才gx
。
计算的余数比测试素性便宜,所以我们会交换两个操作:
pe3 n = last [x | x <- [2 .. isqrt n], rem n x == 0, isPrime x]
这种算法可能参与具体的数字工作,但不幸的是,一般不正确-说为9000009,其整数平方根是3000,它会返回101,但9901是正确的答案(即9901是9000009的最大素因子不是101)。
我们首先关注于寻找最小的首要因素,而不是:
pe3a n = head ([x | x <- [2 .. isqrt n], rem n x == 0, isPrime x] ++ [n])
为什么( ... ++ [n])
( ++
意列出的串联)? 因为如果n
本身是素数,没有除数将全部找到,第一个列表会回来空, []
在这种情况下,答案一定是n
本身。 但如果不是,那么答案是第一个(即head
除数列表)。 当然,当我们发现,我们并不需要继续寻找更多。 只要一个就够了,如果最小的是我们所需要的。
OK,所以想它(在一个假想的懒惰伪翻译),我们得到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)
这样我们就得到第二三回头,及数由发现除数再次分开。
> pe3b (3, 1000001)
(101,9901)
发现下一个素因子是101,而现在因式分解的数量101分之1000001= 9901我们再一次从最后发现除数,101开始,因为所有的小的都已经尝试过:
> pe3b (101, 9901)
(9901,1)
有趣。 isqrt(9901) == 99
,列表[101 .. 99]
是空的,所以结果是立即产生的。 9901是本身高于100的第一因素,在上述1的事实,因为以前所有的号码都已经尝试过,在继承和分割出来。 这意味着9901是素数,没有必要对其进行测试素性。
事实上,该算法发现所有的因素都保证用同样的理由是施工黄金 ,和所有的通话isPrime
是多余的。
难道还需要注意,这是在这里进行的最大数师(求余运算),为101 - 3000 不不仅是我们新的算法是正确的,也更有效!
现在,您可以在方案代号这种算法重复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
预解码步骤开始是一个函数的重复应用的高次模式,直到谓词被满足( ((== 1) . snd)
表示结果的第二分量等于1)。 它通常是编码方案名为let
。
要查看计算的整个历史, iterate
步开始是收集所有的中期业绩另一种模式(与初始值,这是我们不需要的,所以我们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
简单的答案:
$ factor 600851475143
600851475143: 71 839 1471 6857
更严重的答案:你的prime?
功能确实破裂; 我甚至不能肯定什么它试图做。 (另外,你(= n 2)
测试是来不及有用:在(even? n)
测试已经胜过它。)
我的建议是:实现埃拉托色尼的筛 。 下面是我的实现 。
文章来源: Racket Programming. Where am I going wrong?