我已经把这个问题写成了作业:
费马在1643年采用了另一种分解方法。它更多 适合寻找比小的因素更大的因素。假设n是奇数 数量和那个n = u×v。由此得出n = x ^ 2 - y ^ 2,其中x =(u + v)/ 2和y =(v - u)/ 2都是整数(为什么?)。费马的方法包括系统地搜索最小值 x为y,使得x ^ 2-y ^ 2 = n且0≤y<1。 X
练习11. x的最小可能值是什么,即 价值我们应该开始搜索?假设在某个阶段 搜索范围已缩小到x≥p和y≥q。设r = p ^ 2 - q ^ 2 - n。如果 r = 0,然后我们完成了。如果r < 0,我们应该如何改变p或q?和 我们如何改变r来维持r = p ^ 2 - q ^ 2 - n?如果r>,那该怎么办? 0? 为什么这种方法可以保证终止所有奇数n?设计一个 功能搜索使搜索p q r执行搜索。于是 设计一个函数fermat,用于返回给定奇数的两个因子 号。
这是我到目前为止所做的:
type Factors = (Integer, Integer)
search :: Integer -> Integer -> Integer -> Integer -> Factors
search n p q r
| r == 0 = (p-q,p+q)
| r < 0 = search n a b c
| otherwise = search n d b e
where a = p+1 ; b = isqrt (q*q+2*(p-1)+1) ; c = (a*a-b*b-n) ;
d = p-1 ; e = (d*d-b*b-n)
isqrt :: Integer -> Integer
isqrt = truncate . sqrt . fromInteger
fermat :: Integer -> Factors
fermat n
| n == 0 = (0,0)
| otherwise = search n p q r
where p = isqrt(n) ; q = 1 ; r = (p*p-q*q-n)
这适用于某些数字,如33(我按预期得到(3,11))但不适用于其他像99(我得到(1,99)而不是(9,11))。我想我需要为q的初始值使用不同的东西。一些提示将不胜感激。
我尝试将q的初始值更改为isqrt( abs(p*p-n))
,但这仍然是99(3,33),这是不对的。
答案 0 :(得分:1)
正如Daniel Fischer在他的提示中所说,搜索从平方根开始并增加。这是算法,我将留给你翻译成Haskell:
function fermat(n)
s = floor(sqrt(n))
u, v, r = 2*s+1, 1, s*s-n
repeat
if r > 0 then v, r = v+2, r-v
else if r < 0 then u, r = u+2, r+u
else return (u+v-2)/2, (u-v)/2
请注意,此算法返回的两个因子可能是也可能不是素数;如果返回值为 n 且为1,则输入 n 为prime。我在my blog讨论这个算法。请注意,费马的算法是找出数字因子的最差方法之一;甚至试验除法通常也更快,除了 n 是半素数且具有相似幅度的两个因子的情况。