Prime number test performance on negative integers

Please explain why this fails for negative numbers. By fails I mean it starts eating RAM infinitely until either me or OOM kills it. If you replace `m1` definition with the one commented out, the code will fail for positive integers as well, which is very frustrating. import System.Environment isPrime :: Int -> (Bool, String) isPrime n = let ll n = k + 1 : k + 5 : ll (n + 1) where k = 6 * n + 1 l = 2 : 3 : 5 : ll 1 q (i:is) | i * i > n = (True, "it is") | (n `rem` i) == 0 = (False, "divisible by " ++ show i) | otherwise = q is in q l main = getArgs >>= \argv -> let f True = "primal" f False = "not primal" m0 = map (\x -> read x :: Int) argv m1 = m0 --m1 = -- map -- (\x -> -- if x < 0 -- then -x -- else x) -- m0 m2 = map isPrime m1 msg (x, (y0, y1)) = x ++ " is " ++ f y0 ++ " because " ++ y1 in mapM_ putStrLn $ map msg (zip argv m2)

Hello Pratima, Il 11 dicembre 2023 alle 19:24 Folsk Pratima ha scritto:
Please explain why this fails for negative numbers. By fails I mean it starts eating RAM infinitely until either me or OOM kills it. If you replace `m1` definition with the one commented out, the code will fail for positive integers as well, which is very frustrating.
I have replaced m1 definition with the commented one, and it works on my machine. f@x270:/tmp/prova$ ./prime -4 -4 is not primal because divisible by 2 How are you invoking the program? A few additional notes (run `hlint` for more)
main = getArgs >>= \argv ->
I don’t mind `>>=` but with `do` notation and `traceM/traceShowM` it is easier to debug your programs.
--m1 = -- map -- (\x -> -- if x < 0 -- then -x -- else x) -- m0
More compact: `m1 = map abs m0`
msg (x, (y0, y1)) = x ++ " is " ++ f y0 ++ " because " ++ y1
Ancillary functions like this one can go in the `where` section. Ciao —F

Hello Pratima,
Il 11 dicembre 2023 alle 19:24 Folsk Pratima ha scritto:
Please explain why this fails for negative numbers. By fails I mean it starts eating RAM infinitely until either me or OOM kills it. If you replace `m1` definition with the one commented out, the code will fail for positive integers as well, which is very frustrating.
I have replaced m1 definition with the commented one, and it works on my machine.
f at x270:/tmp/prova$ ./prime -4 -4 is not primal because divisible by 2
How are you invoking the program?
A few additional notes (run `hlint` for more)
main = getArgs >>= \argv ->
I don’t mind `>>=` but with `do` notation and `traceM/traceShowM` it is easier to debug your programs.
--m1 = -- map -- (\x -> -- if x < 0 -- then -x -- else x) -- m0
More compact: `m1 = map abs m0`
msg (x, (y0, y1)) = x ++ " is " ++ f y0 ++ " because " ++ y1
Ancillary functions like this one can go in the `where` section. Ciao —F
I have been just going to remedy and send the actual number I was using
for testing, sorry for this. Assuming the binary is called a.out,
./a.out 4394853075948683624652562564254523466839834983
I have not immediately guessed that it overflows, so after playing a
minute with it I figured another number -- 1506491439391566589 -- that
breaks even while being positive. And it does not matter if
`m1 = m0` or `m1 = map abs m0`.
I have come up with another definition, based on the `primals`
definition on haskell.org main page that I have not noticed until now.
isPrime6 :: Int -> (Bool, String)
isPrime6 n = test (f [2 ..])
where
f (x:xs) = x : f [y | y <- xs, (y `rem` x) /= 0]
test (x:xs)
| x > n = (False, "it is not")
| x == n = (True, "it is")
| otherwise = test xs
Testing it with 1506491439391566589 makes it look like the code is
going to run forever, but at least it does not take all of your RAM. I
dare suspect the problem is somewhere around having a separate variable
for the `l` list, which does not allow haskell to forget used members.
I am not sure about anything however.
Also, the fact that the code runs forever nonetheless is very sad,
because C equivalent taken from wiki[1] calculates the whole things
almost immediately. The C code is ultra simplified:
#include

Il 11 dicembre 2023 alle 20:24 Folsk Pratima ha scritto:
Also, the fact that the code runs forever nonetheless is very sad, because C equivalent taken from wiki[1] calculates the whole things almost immediately. The C code is ultra simplified:
#include
#include int IsPrime(int64_t n) { if (n == 2 || n == 3) return 1; if (n <= 1 || n % 2 == 0 || n % 3 == 0) return 0;
for (int i = 5; i * i <= n; i += 6) { if (n % i == 0 || n % (i + 2) == 0) return 0; }
return 1; }
int main () { printf ("1506491439391566589: %d\n", IsPrime (1506491439391566589)); }
Let’s implement the algorithm in Haskell, shall we? import System.Environment isPrimeWiki :: Integer -> Bool isPrimeWiki 2 = True isPrimeWiki 3 = True isPrimeWiki n | n <= 1 || rem n 2 == 0 || rem n 3 == 0 = False isPrimeWiki n = let f i | i^2 > n = True | rem n i == 0 || rem n (i+2) == 0 = False | otherwise = True in f 5 main :: IO () main = do [n] <- getArgs print $ isPrimeWiki (read n) then f@x270:/tmp/prova$ time ./prime 1506491439391566589 True real 0m0.014s user 0m0.001s sys 0m0.005s

Il 11 dicembre 2023 alle 20:24 Folsk Pratima ha scritto:
Also, the fact that the code runs forever nonetheless is very sad, because C equivalent taken from wiki[1] calculates the whole things almost immediately. The C code is ultra simplified:
#include
#include int IsPrime(int64_t n) { if (n == 2 || n == 3) return 1; if (n <= 1 || n % 2 == 0 || n % 3 == 0) return 0;
for (int i = 5; i * i <= n; i += 6) { if (n % i == 0 || n % (i + 2) == 0) return 0; }
return 1; }
int main () { printf ("1506491439391566589: %d\n", IsPrime (1506491439391566589)); }
Let’s implement the algorithm in Haskell, shall we?
import System.Environment
isPrimeWiki :: Integer -> Bool isPrimeWiki 2 = True isPrimeWiki 3 = True isPrimeWiki n | n <= 1 || rem n 2 == 0 || rem n 3 == 0 = False isPrimeWiki n = let f i | i^2 > n = True | rem n i == 0 || rem n (i+2) == 0 = False | otherwise = True in f 5
main :: IO () main = do [n] <- getArgs print $ isPrimeWiki (read n)
then
f at x270:/tmp/prova$ time ./prime 1506491439391566589 True
real 0m0.014s user 0m0.001s sys 0m0.005s Ahem,
#include

Il 11 dicembre 2023 alle 21:41 Folsk Pratima ha scritto:
Ahem,
Woops, I messed up that `otherwise`. import System.Environment isPrimeWiki :: Integer -> Bool isPrimeWiki 2 = True isPrimeWiki 3 = True isPrimeWiki n | n <= 1 || rem n 2 == 0 || rem n 3 == 0 = False isPrimeWiki n = let f i | i^2 > n = True | rem n i == 0 || rem n (i+2) == 0 = False | otherwise = f (i+1) in f 5 main :: IO () main = do [n] <- getArgs print $ isPrimeWiki (read n) Still, no sweat computing that: f@x270:/tmp/prova$ time ./prime 1506491439391566589 False real 0m0.014s user 0m0.000s sys 0m0.005s
participants (2)
-
Folsk Pratima
-
Francesco Ariis