费马原始性测试Haskell

时间:2017-12-05 16:33:05

标签: haskell math primality-test

我已经实现了以下两个函数来确定n是否为fermat素数(如果为真,则返回n,否则返回-1),但它总是返回-1,无法找出原因(gc是a功能taht计算gcd)

fermatPT :: Int -> Int
fermatPT n = fermatPT' n list
  where
    list = [a | a <- [1..n-1]]

-- | heper function
fermatPT' :: Int -> [Int] -> Int
fermatPT' n l      | gc (n, head l) == 1 && fermatTest n (head l) = fermatPT' n (tail l)
                   | null l                                       = n
                   | otherwise                                    = -1
                where
                  fermatTest n a = mod (a^(n-1)) n == 1

1 个答案:

答案 0 :(得分:2)

您的函数应返回一个布尔值,指示给定的数字是否为素数。如果这样做,您可以使用all函数将其定义为

fermatPT :: Integer -> Bool
fermatPT n = all (fermatTest n) (filter (\a -> gcd n a == 1) [1..n-1])
             where fermatTest n a = mod (a^(n-1)) n == 1

gcd在前奏中定义。

all避免了显式递归,要求您一次将测试应用于[1..n-1]的一个元素;它的定义是有效的

all _ [] = True
all p (x:xs) = p x && all p xs

请注意mod (a ^ (n - 1)) n效率低下,因为它可能需要先计算一个非常大的数字,然后再将其缩小到范围[0..n-1]。相反,利用ab mod n == (a mod n * b mod n) mod n这一事实,并在每次乘法后减少该值。实现这一目标的一种方法(不是最快,但很简单):

modN :: Integer -> Integer -> Integer -> Integer
modN a 0 _ = 1
modN a b n = ((a `mod` n) * (modN a (b - 1) n)) `mod` n

然后使用

fermatTest n a = modN a (n-1) n == 1

请注意,您可以使用此功能(使用Int代替Integer)来正确实施fermatPT :: Int -> Bool;虽然输入仍然只限于较小的整数,但它不会受到溢出的影响。