From folsk0pratima at cock.li Mon Dec 11 17:24:17 2023 From: folsk0pratima at cock.li (Folsk Pratima) Date: Mon, 11 Dec 2023 19:24:17 +0200 Subject: [Haskell-beginners] Prime number test performance on negative integers Message-ID: <20231211192417.12af6c2e@folsk0pratima.cock.li> 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) From fa-ml at ariis.it Mon Dec 11 17:55:21 2023 From: fa-ml at ariis.it (Francesco Ariis) Date: Mon, 11 Dec 2023 18:55:21 +0100 Subject: [Haskell-beginners] Prime number test performance on negative integers In-Reply-To: <20231211192417.12af6c2e@folsk0pratima.cock.li> References: <20231211192417.12af6c2e@folsk0pratima.cock.li> Message-ID: 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 From folsk0pratima at cock.li Mon Dec 11 18:24:13 2023 From: folsk0pratima at cock.li (Folsk Pratima) Date: Mon, 11 Dec 2023 20:24:13 +0200 Subject: [Haskell-beginners] Prime number test performance on negative integers In-Reply-To: Message-ID: <20231211202413.576b05cb@folsk0pratima.cock.li> >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 #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)); } I did not even do anything special to compile it, just `gcc`. With haskell I supplied the `-O2` flag to `ghc`. 1. https://en.wikipedia.org/wiki/Primality_test From fa-ml at ariis.it Mon Dec 11 18:48:07 2023 From: fa-ml at ariis.it (Francesco Ariis) Date: Mon, 11 Dec 2023 19:48:07 +0100 Subject: [Haskell-beginners] Prime number test performance on negative integers In-Reply-To: <20231211202413.576b05cb@folsk0pratima.cock.li> References: <20231211202413.576b05cb@folsk0pratima.cock.li> Message-ID: 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 From folsk0pratima at cock.li Mon Dec 11 19:41:00 2023 From: folsk0pratima at cock.li (Folsk Pratima) Date: Mon, 11 Dec 2023 21:41:00 +0200 Subject: [Haskell-beginners] Prime number test performance on negative integers In-Reply-To: Message-ID: <20231211214100.4f057c3e@folsk0pratima.cock.li> >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 #include #include int IsPrime(int64_t n, char **msg) { 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) { sprintf (*msg, "divisible by %d", i); return 0; } if (n % (i + 2) == 0) { sprintf (*msg, "divisible by %d", i + 2); return 0; } } return 1; } int main () { char *msg[1]; msg[0] = malloc (sizeof (char) * 128); sprintf (msg[0], "success"); int res; int64_t num; char numstr[] = "1506491439391566589"; num = 1506491439391566589; res = IsPrime (num, msg); printf ("%s: %d: %s\n", numstr, res, msg[0]); } tells me the number is divisible by 13 and is *not* primal. The qalculate tells me pretty much the same! From fa-ml at ariis.it Mon Dec 11 20:25:33 2023 From: fa-ml at ariis.it (Francesco Ariis) Date: Mon, 11 Dec 2023 21:25:33 +0100 Subject: [Haskell-beginners] Prime number test performance on negative integers In-Reply-To: <20231211214100.4f057c3e@folsk0pratima.cock.li> References: <20231211214100.4f057c3e@folsk0pratima.cock.li> Message-ID: 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 at x270:/tmp/prova$ time ./prime 1506491439391566589 False real 0m0.014s user 0m0.000s sys 0m0.005s