The GHC Haskell and OCaml compilers do not have builtin popcount support, so again I precomputed the bit pop count for each ASCII letter. Using the same ~9 Mb 4x concatenation of /usr/share/dict/words from last time I measured the performance of the resultant code. This time, the test machine was a Macbook Pro 2.16 GHz with 2 Gb of RAM. The microprocessor is a Core Duo T7400 which has no support for the popcnt instruction anyway.
This is a follow-on post to my experiments with popcount and hash maps in Python, C++, and Ruby in Part 1
| Description | Execution Time (ms) |
|---|---|
| GHC Map Lookup Only/Precomputed | 2568 |
| OCaml Map Lookup Only/Precomputed | 866 |
| Python Precomputed | 5418 |
| g++ | 843 |
| g++ -O3 | 505 |
OCaml is fairly competitive with the unoptimized g++ version. GHC lags quite a bit, but fares alright all things considered. The version of GHC I used was 7.0.4. OCaml was version 3.12.1.
Haskell
import Data.Bits
import System.IO
import Data.Char
import System.IO.Error
import Control.Monad
import Data.Map ((!), insert, empty, fromList)
letters = fromList
[('A', 2), ('C', 3),('B', 2),( 'E', 3),( 'D', 2),( 'G', 4),( 'F', 3),( 'I', 3),( 'H', 2),( 'K', 4),( 'J', 3),( 'M', 4),( 'L', 3),( 'O', 5),( 'N', 4),( 'Q', 3),( 'P', 2),( 'S', 4),( 'R', 3),( 'U', 4),( 'T', 3),( 'W', 5),( 'V', 4),( 'Y', 4),( 'X', 3),( '[', 5),( 'Z', 4),( ']', 5),( '\\', 4),( '_', 6),( '^', 5),( 'a', 3),( '`', 2),( 'c', 4),( 'b', 3),( 'e', 4),( 'd', 3),( 'g', 5),( 'f', 4),( 'i', 4),( 'h', 3),( 'k', 5),( 'j', 4),( 'm', 5),( 'l', 4),( 'o', 6),( 'n', 5),( 'q', 4),( 'p', 3),( 's', 5),( 'r', 4),( 'u', 5),( 't', 4),( 'w', 6),( 'v', 5),( 'y', 5),( 'x', 4),( 'z', 5)]
popcount :: Int -> Int
popcount n =
let popcountAcc n acc =
if n == 0 then acc else popcountAcc (shiftR n 1) (acc + (n .&. 1))
in popcountAcc n 0
loop h acc =
do
eof <- hIsEOF h
if eof then return acc
else do line <- hGetLine h
let x = sum (map ((!) letters) line)
let acc' = x+acc
loop h acc'
main = do
h <- openFile "words4" ReadMode
acc <- loop h 0
hClose h
return 0
OCaml
let h = open_in("words4")
(* From OCaml Batteries *)
let explode s =
let rec exp i l =
if i < 0 then l else exp (i - 1) (s.[i] :: l) in
exp (String.length s - 1) []
let rec loop() =
let w = try Some (input_line h) with End_of_file -> None
in match w
with None -> ()
| Some w ->
let n = List.fold_left (+) 0
(List.map (fun c -> M.find c letters)
(explode w))
in loop()
let main =
(loop();
close_in h)
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.