0

I have implemented the following two functions for establishing if n is a fermat prime number (will return n if its true, -1 if not), but it returns always -1, can't figure out why (gc is a funct taht calculates 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
jberryman
  • 16,334
  • 5
  • 42
  • 83

1 Answers1

2

Your function should return a boolean indicating if the given number is a prime. If you do that, you can use the all function to define this simply as

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 is defined in the Prelude.

all avoids the explicit recursion that requires you to apply the test to one element of [1..n-1] at a time; its definition is effectively

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

Note that mod (a ^ (n - 1)) n is inefficient, since it may require computing an absurdly large number before ultimately reducing it to the range [0..n-1]. Instead, take advantage of the fact that ab mod n == (a mod n * b mod n) mod n, and reduce the value after each multiplication. One way to implement this (not the fastest, but it's simple):

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

Then use

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

Note that you could use this (with Int instead of Integer) to correctly implement fermatPT :: Int -> Bool; although the input would still be restricted to smaller integers, it won't suffer from overflow.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • I know it should return a bool, but the second part of the exercise is to return the lower fermat witness if n is not prime. – Eros Fabrici Dec 06 '17 at 11:18
  • And still this solution doesn't work unfortunately, fermatPT 53 return false, should return True – Eros Fabrici Dec 06 '17 at 12:07
  • You are running into overflow errors with the naive computation of `a^(n-1) mod n`; changing the type signature to `Integer -> Bool` seems to fix it. (For example, `52 ^ 52 :: Int == 0`, while `52 ^ 52 :: Integer == 170676555274132171974277914691501574771358362295975962674353045737940041855191232907575296`). – chepner Dec 06 '17 at 13:24