在Haskell中实现Fermat分解

时间:2012-10-21 10:32:14

标签: haskell factorization

我已经把这个问题写成了作业:

  

费马在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),这是不对的。

1 个答案:

答案 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 是半素数且具有相似幅度的两个因子的情况。