我已经实现了以下两个函数来确定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
答案 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
;虽然输入仍然只限于较小的整数,但它不会受到溢出的影响。