🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.functional
Article #1125

Haskell optimization (mandelbrot generator)

#1125
From: jtdubs
Date: Tue, 27 Jun 2006 03:16
72 lines
3481 bytes
I am teaching myself Haskell and decided to write a Mandelbrot
generator as a learning exercise.

It works fine and the code is nice and short, but I'm not happy with
the performance.  I am generating a 131 x 101 pixel image (-2 to 1.6 on
the real axis and -1 to 1 on the imaginary axis with a step size of
0.02).

I wrote an equivalent C program real quick, just for the sake of
comparison.

I compiled the C code with: gcc -O2 fractal.c -o fractal
I compiled the Haskell code with: ghc -funbox-strict-fields -O2
fractal.hs -o fractal

The speeds are:
C: 0.05s
Haskell: 8.3s

So, that's 166x slower.  I'm hoping someone can give me some pointers
to help me optimize this. I've tried:

1. Passing the file handle through fractal and escape so that escape
returns IO (), fractal returns IO (), the map calls are changed to
mapM_ and escape just prints its result directly with hPutStrLn.  My
theory was that the consing of the result list was slowing the app
down.  However, this change did not affect the speed at all.

2. Changing from double's to floats.  This actually slowed things down.
 The GHC manual backed this up by saying that Double's are much more
heavily optimized than floats, especially complex double compared to
complex float.

Any other ideas?  Oh, and since I'm a Haskell newbie, any stylistic
suggestions or other constructive criticism would be
welcome/appreciated.

Thanks,

Justin Dubs


Here's the code:

import Complex
import IO

type Dimensions = (Double, Double, Double, Double) -- top, left,
bottom, right
type Resolution = Double

fractal :: Dimensions -> Resolution -> [[Int]]
fractal (t,l,b,r) d = map (\y -> map (\x -> escape 255 (0:+0) (x:+y))
[l,l+d..r]) [b,b+d..t]
  where
  escape :: Int -> Complex Double -> Complex Double -> Int
  escape 0 _ _ = 0
  escape i z c = if (magnitude z > 2) then i else escape (i-1) (z*z+c)
c

make_pgm :: String -> [[Int]] -> IO ()
make_pgm f v = do
                 h <- openFile f WriteMode
                 hPutStrLn h "P2"
                 hPutStrLn h (show (length (head v)) ++ " " ++ show
(length v))
                 hPutStrLn h "255"
                 mapM_ (mapM_ ((hPutStrLn h) . show)) v
                 hClose h

main :: IO ()
main = make_pgm "foo.pgm" (fractal (1,-2,-1,0.6) 0.02)
Technical Details
Message-ID: <1151378213.631887.29960@r2g2000cwb.googlegroups.com>
Path: arc1-ca.pugleaf.net!g2news2.google.com!postnews.google.com!r2g2000cwb.googlegroups.com!not-for-mail

Show Full Headers
Complete Article Headers
X-Google-Thread: 107f24,c4c6b7c72553cb95,start
X-Google-Thread: 10707f,c4c6b7c72553cb95,start
X-Google-Attributes: gid107f24,gid10707f,public
X-Google-Language: ENGLISH,ASCII-7-bit
Path: arc1-ca.pugleaf.net!g2news2.google.com!postnews.google.com!r2g2000cwb.googlegroups.com!not-for-mail
From: jtdubs@gmail.com
Newsgroups: comp.lang.functional,fa.haskell
Subject: Haskell optimization (mandelbrot generator)
Date: 26 Jun 2006 20:16:53 -0700
Organization: http://groups.google.com
Lines: 73
Message-ID: <1151378213.631887.29960@r2g2000cwb.googlegroups.com>
NNTP-Posting-Host: 71.77.94.5
Mime-Version: 1.0
Content-Type: text/plain; charset="iso-8859-1"
X-Trace: posting.google.com 1151378218 957 127.0.0.1 (27 Jun 2006 03:16:58 GMT)
X-Complaints-To: groups-abuse@google.com
NNTP-Posting-Date: Tue, 27 Jun 2006 03:16:58 +0000 (UTC)
User-Agent: G2/0.2
X-HTTP-UserAgent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418 (KHTML, like Gecko) Safari/417.9.3,gzip(gfe),gzip(gfe)
Complaints-To: groups-abuse@google.com
Injection-Info: r2g2000cwb.googlegroups.com; posting-host=71.77.94.5;
   posting-account=6Ga3uw0AAADBBQ_AgT5Nx96fNWangc6s